';
@@ -1340,6 +1574,14 @@ static function prepareReportBody($options, $comment = null)
}
if ($options['show_client']) $body .= '| '.$subtotals[$prev_grouped_by]['client'].' | ';
if ($options['show_project']) $body .= ''.$subtotals[$prev_grouped_by]['project'].' | ';
+ // Project custom fields.
+ if ($custom_fields && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ $checkbox_control_name = 'show_'.$field_name;
+ if ($options[$checkbox_control_name]) $body .= ' | ';
+ }
+ }
if ($options['show_task']) $body .= ''.$subtotals[$prev_grouped_by]['task'].' | ';
// Time custom fields.
if ($custom_fields && $custom_fields->timeFields) {
@@ -1354,6 +1596,7 @@ static function prepareReportBody($options, $comment = null)
if ($options['show_duration']) $body .= ''.$subtotals[$cur_grouped_by]['time'].' | ';
if ($options['show_work_units']) $body .= ''.$subtotals[$cur_grouped_by]['units'].' | ';
if ($show_note_column) $body .= ' | ';
+ if ($show_cost_per_hour) $body .= ' | ';
if ($options['show_cost']) {
$body .= '';
$body .= ($canViewReports || $isClient) ? $subtotals[$cur_grouped_by]['cost'] : $subtotals[$cur_grouped_by]['expenses'];
@@ -1382,6 +1625,14 @@ static function prepareReportBody($options, $comment = null)
}
if ($options['show_client']) $body .= ' | | ';
if ($options['show_project']) $body .= ' | ';
+ // Project custom fields.
+ if ($custom_fields && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ $checkbox_control_name = 'show_'.$field_name;
+ if ($options[$checkbox_control_name]) $body .= ' | ';
+ }
+ }
if ($options['show_task']) $body .= ' | ';
// Time custom fields.
if ($custom_fields && $custom_fields->timeFields) {
@@ -1396,6 +1647,7 @@ static function prepareReportBody($options, $comment = null)
if ($options['show_duration']) $body .= ''.$totals['time'].' | ';
if ($options['show_work_units']) $body .= ''.$totals['units'].' | ';
if ($show_note_column) $body .= ' | ';
+ if ($show_cost_per_hour) $body .= ' | ';
if ($options['show_cost']) {
$body .= ''.htmlspecialchars($user->currency).' ';
$body .= ($canViewReports || $isClient) ? $totals['cost'] : $totals['expenses'];
@@ -1511,19 +1763,31 @@ static function getReportOptions($bean) {
// Construct one by one.
$options['name'] = null; // No name required.
- $options['user_id'] = $user->id; // Not sure if we need user_id here. Fav reports use it to recycle $user object in cron.php.
- $options['client_id'] = $bean->getAttribute('client');
- $options['project_id'] = $bean->getAttribute('project');
- $options['task_id'] = $bean->getAttribute('task');
- $options['billable'] = $bean->getAttribute('include_records');
- $options['invoice'] = $bean->getAttribute('invoice');
- $options['paid_status'] = $bean->getAttribute('paid_status');
- $options['approved'] = $bean->getAttribute('approved');
+ // $options['user_id'] = $user->id; // We don't use user_id in regular reports. But fav reports use it to recycle $user object in cron.php.
+ $options['client_id'] = (int)$bean->getAttribute('client');
+
+ // Handle selected projects. Just in case check both "project[]" and "project".
+ $selected_projects_in_bean = $bean->getAttribute('project[]');
+ if (is_array($selected_projects_in_bean) && !empty($selected_projects_in_bean[0])) {
+ $options['project_ids'] = join(',', $selected_projects_in_bean);
+ }
+ $selected_projects_in_bean = $bean->getAttribute('project');
+ if (is_array($selected_projects_in_bean) && !empty($selected_projects_in_bean[0])) {
+ $options['project_ids'] = join(',', $selected_projects_in_bean);
+ }
+ // $options['project_id'] = (int)$bean->getAttribute('project'); // This was here for a single project select.
+
+ $options['task_id'] = (int)$bean->getAttribute('task');
+ $options['billable'] = (int)$bean->getAttribute('include_records');
+ $options['invoice'] = (int)$bean->getAttribute('invoice');
+ $options['paid_status'] = (int)$bean->getAttribute('paid_status');
+ $options['approved'] = (int)$bean->getAttribute('approved');
if ($user->isPluginEnabled('ap') && $user->isClient() && !$user->can('view_client_unapproved'))
$options['approved'] = 1; // Restrict clients to approved records only.
- $options['timesheet'] = $bean->getAttribute('timesheet');
+ $options['timesheet'] = (int)$bean->getAttribute('timesheet');
$active_users_in_bean = $bean->getAttribute('users_active');
+ $users = '';
if ($active_users_in_bean && is_array($active_users_in_bean)) {
$users = join(',', $active_users_in_bean);
}
@@ -1534,24 +1798,25 @@ static function getReportOptions($bean) {
}
if ($users) $options['users'] = $users;
- $options['period'] = $bean->getAttribute('period');
+ $options['period'] = (int)$bean->getAttribute('period');
$options['period_start'] = $bean->getAttribute('start_date');
$options['period_end'] = $bean->getAttribute('end_date');
- $options['show_client'] = $bean->getAttribute('chclient');
- $options['show_invoice'] = $bean->getAttribute('chinvoice');
- $options['show_approved'] = $bean->getAttribute('chapproved');
- $options['show_paid'] = $bean->getAttribute('chpaid');
- $options['show_ip'] = $bean->getAttribute('chip');
- $options['show_project'] = $bean->getAttribute('chproject');
- $options['show_start'] = $bean->getAttribute('chstart');
- $options['show_duration'] = $bean->getAttribute('chduration');
- $options['show_cost'] = $bean->getAttribute('chcost');
- $options['show_task'] = $bean->getAttribute('chtask');
- $options['show_end'] = $bean->getAttribute('chfinish');
- $options['show_note'] = $bean->getAttribute('chnote');
- $options['show_work_units'] = $bean->getAttribute('chunits');
- $options['show_timesheet'] = $bean->getAttribute('chtimesheet');
- $options['show_files'] = $bean->getAttribute('chfiles');
+ $options['note_containing'] = $bean->getAttribute('note_containing');
+ $options['show_client'] = (int)$bean->getAttribute('chclient');
+ $options['show_invoice'] = (int)$bean->getAttribute('chinvoice');
+ $options['show_approved'] = (int)$bean->getAttribute('chapproved');
+ $options['show_paid'] = (int)$bean->getAttribute('chpaid');
+ $options['show_ip'] = (int)$bean->getAttribute('chip');
+ $options['show_project'] = (int)$bean->getAttribute('chproject');
+ $options['show_start'] = (int)$bean->getAttribute('chstart');
+ $options['show_duration'] = (int)$bean->getAttribute('chduration');
+ $options['show_cost'] = (int)$bean->getAttribute('chcost');
+ $options['show_task'] = (int)$bean->getAttribute('chtask');
+ $options['show_end'] = (int)$bean->getAttribute('chfinish');
+ $options['show_note'] = (int)$bean->getAttribute('chnote');
+ $options['show_work_units'] = (int)$bean->getAttribute('chunits');
+ $options['show_timesheet'] = (int)$bean->getAttribute('chtimesheet');
+ $options['show_files'] = (int)$bean->getAttribute('chfiles');
// Prepare custom field options.
if ($user->isPluginEnabled('cf')) {
@@ -1563,8 +1828,14 @@ static function getReportOptions($bean) {
foreach ($custom_fields->timeFields as $timeField) {
$control_name = 'time_field_'.$timeField['id'];
$checkbox_control_name = 'show_'.$control_name;
- $options[$control_name] = $bean->getAttribute($control_name);
- $options[$checkbox_control_name] = $bean->getAttribute($checkbox_control_name);
+ if ($timeField['type'] == CustomFields::TYPE_DROPDOWN) {
+ // Cast to int for a dropdown for extra security.
+ $options[$control_name] = (int)$bean->getAttribute($control_name);
+ } elseif ($timeField['type'] == CustomFields::TYPE_TEXT) {
+ // No need to cast to int for a text field.
+ $options[$control_name] = $bean->getAttribute($control_name);
+ }
+ $options[$checkbox_control_name] = (int)$bean->getAttribute($checkbox_control_name);
}
}
@@ -1573,18 +1844,38 @@ static function getReportOptions($bean) {
foreach ($custom_fields->userFields as $userField) {
$control_name = 'user_field_'.$userField['id'];
$checkbox_control_name = 'show_'.$control_name;
- $options[$control_name] = $bean->getAttribute($control_name);
- $options[$checkbox_control_name] = $bean->getAttribute($checkbox_control_name);
+ if ($userField['type'] == CustomFields::TYPE_DROPDOWN) {
+ // Cast to int for a dropdown for extra security.
+ $options[$control_name] = (int)$bean->getAttribute($control_name);
+ } elseif ($userField['type'] == CustomFields::TYPE_TEXT) {
+ // No need to cast to int for a text field.
+ $options[$control_name] = $bean->getAttribute($control_name);
+ }
+ $options[$checkbox_control_name] = (int)$bean->getAttribute($checkbox_control_name);
}
}
- // TODO: add project fields here.
+ // Project fields.
+ if ($custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $control_name = 'project_field_'.$projectField['id'];
+ $checkbox_control_name = 'show_'.$control_name;
+ if ($projectField['type'] == CustomFields::TYPE_DROPDOWN) {
+ // Cast to int for a dropdown for extra security.
+ $options[$control_name] = (int)$bean->getAttribute($control_name);
+ } elseif ($projectField['type'] == CustomFields::TYPE_TEXT) {
+ // No need to cast to int for a text field.
+ $options[$control_name] = $bean->getAttribute($control_name);
+ }
+ $options[$checkbox_control_name] = (int)$bean->getAttribute($checkbox_control_name);
+ }
+ }
}
$options['group_by1'] = $bean->getAttribute('group_by1');
$options['group_by2'] = $bean->getAttribute('group_by2');
$options['group_by3'] = $bean->getAttribute('group_by3');
- $options['show_totals_only'] = $bean->getAttribute('chtotalsonly');
+ $options['show_totals_only'] = (int)$bean->getAttribute('chtotalsonly');
return $options;
}
@@ -1592,6 +1883,9 @@ static function getReportOptions($bean) {
static function verifyBean($bean) {
global $user;
+ // Check period control.
+ if (!ttValidInteger($bean->getAttribute('period'), true)) return false;
+
// Check users.
$active_users_in_bean = (array) $bean->getAttribute('users_active');
$inactive_users_in_bean = (array) $bean->getAttribute('users_inactive');
@@ -1612,13 +1906,166 @@ static function verifyBean($bean) {
}
}
- // TODO: add additional checks here. Perhaps do it before saving the bean for consistency.
+ // Check fav report id.
+ $fav_report_id = $bean->getAttribute('favorite_report');
+ if (!($fav_report_id == -1 || (ttValidInteger($fav_report_id) && ttFavReportHelper::get($fav_report_id)))) return false;
+
+ // Check client id.
+ if (!ttValidInteger($bean->getAttribute('client'), true)) return false;
+
+ // Check billable control.
+ if (!ttValidInteger($bean->getAttribute('include_records'), true)) return false;
+
+ // Check invoiced / not invoiced control.
+ if (!ttValidInteger($bean->getAttribute('invoice'), true)) return false;
+
+ // Check selected project ids. Just in case check both project[] and project.
+ $selectedProjects = $bean->getAttribute('project');
+ if (is_array($selectedProjects)) {
+ foreach ($selectedProjects as $singleProjectId) {
+ if (!ttValidInteger($singleProjectId, true)) return false;
+ }
+ }
+ $selectedProjects = $bean->getAttribute('project[]');
+ if (is_array($selectedProjects)) {
+ foreach ($selectedProjects as $singleProjectId) {
+ if (!ttValidInteger($singleProjectId, true)) return false;
+ }
+ }
+
+ // Check task id.
+ if (!ttValidInteger($bean->getAttribute('task'), true)) return false;
+
+ // Check paid status control.
+ if (!ttValidInteger($bean->getAttribute('paid_status'), true)) return false;
+
+ // Check approved status control.
+ if (!ttValidInteger($bean->getAttribute('approved'), true)) return false;
+
+ // Check timesheet status control.
+ if (!ttValidInteger($bean->getAttribute('timesheet'), true)) return false;
+
+ // Validate checkboxes.
+ if (!ttValidCheckbox($bean->getAttribute('chclient'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chproject'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chtask'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chstart'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chfinish'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chduration'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chnote'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chunits'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chcost'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chapproved'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chpaid'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chip'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chinvoice'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chtimesheet'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chfiles'))) return false;
+ if (!ttValidCheckbox($bean->getAttribute('chtotalsonly'))) return false;
+
+ // Verify custom field controls.
+ if ($user->isPluginEnabled('cf')) {
+ global $custom_fields;
+ if (!$custom_fields) $custom_fields = new CustomFields();
+
+ // Time fields.
+ if ($custom_fields->timeFields) {
+ foreach ($custom_fields->timeFields as $timeField) {
+ $control_name = 'time_field_'.$timeField['id'];
+ $checkbox_control_name = 'show_'.$control_name;
+ if ($timeField['type'] == CustomFields::TYPE_DROPDOWN) {
+ if (!ttValidInteger($bean->getAttribute($control_name), true))
+ return false;
+ }
+ if (!ttValidCheckbox($bean->getAttribute($checkbox_control_name), true))
+ return false;
+ }
+ }
+
+ // User fields.
+ if ($custom_fields->userFields) {
+ foreach ($custom_fields->userFields as $userField) {
+ $control_name = 'user_field_'.$userField['id'];
+ $checkbox_control_name = 'show_'.$control_name;
+ if ($userField['type'] == CustomFields::TYPE_DROPDOWN) {
+ if (!ttValidInteger($bean->getAttribute($control_name), true))
+ return false;
+ }
+ if (!ttValidCheckbox($bean->getAttribute($checkbox_control_name), true))
+ return false;
+ }
+ }
+
+ // Project fields.
+ if ($custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $control_name = 'project_field_'.$projectField['id'];
+ $checkbox_control_name = 'show_'.$control_name;
+ if ($projectField['type'] == CustomFields::TYPE_DROPDOWN) {
+ if (!ttValidInteger($bean->getAttribute($control_name), true))
+ return false;
+ }
+ if (!ttValidCheckbox($bean->getAttribute($checkbox_control_name), true))
+ return false;
+ }
+ }
+ }
+
+ if (!ttReportHelper::validGroupByOption($bean->getAttribute('group_by1'))) return false;
+ if (!ttReportHelper::validGroupByOption($bean->getAttribute('group_by2'))) return false;
+ if (!ttReportHelper::validGroupByOption($bean->getAttribute('group_by3'))) return false;
+
return true;
}
+ // validGroupByOption is a security function to verify selection options for group by controls.
+ static function validGroupByOption($groupByOption) {
+
+ global $user;
+
+ if ($groupByOption == 'no_grouping' || $groupByOption == 'date' || $groupByOption == 'user' || $groupByOption == 'client' || $groupByOption == 'project' || $groupByOption == 'task' || $groupByOption == null)
+ return true;
+
+ // Verify custom field group by options.
+ if ($user->isPluginEnabled('cf')) {
+ global $custom_fields;
+ if (!$custom_fields) $custom_fields = new CustomFields();
+
+ // Time fields.
+ if ($custom_fields->timeFields) {
+ foreach ($custom_fields->timeFields as $timeField) {
+ $control_name = 'time_field_'.$timeField['id'];
+ if ($groupByOption == $control_name)
+ return true;
+ }
+ }
+
+ // User fields.
+ if ($custom_fields->userFields) {
+ foreach ($custom_fields->userFields as $userField) {
+ $control_name = 'user_field_'.$userField['id'];
+ if ($groupByOption == $control_name)
+ return true;
+ }
+ }
+
+ // Project fields.
+ if ($custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $control_name = 'project_field_'.$projectField['id'];
+ if ($groupByOption == $control_name)
+ return true;
+ }
+ }
+ } // if ($user->isPluginEnabled('cf')) {
+
+ return false;
+ }
+
// makeGroupByKey builds a combined group by key from group_by1, group_by2 and group_by3 values
// (passed in $options) and a row of data ($row obtained from a db query).
static function makeGroupByKey($options, $row) {
+ $group_by_key = '';
if ($options['group_by1'] != null && $options['group_by1'] != 'no_grouping') {
// We have group_by1.
$group_by1 = $options['group_by1'];
@@ -1671,9 +2118,13 @@ static function makeSingleDropdownGroupByPart($dropdown_value, $options) {
static function makeGroupByPart($options) {
if (!ttReportHelper::grouping($options)) return null;
- $group_by_parts .= ttReportHelper::makeSingleDropdownGroupByPart($options['group_by1'], $options);
- $group_by_parts .= ttReportHelper::makeSingleDropdownGroupByPart($options['group_by2'], $options);
- $group_by_parts .= ttReportHelper::makeSingleDropdownGroupByPart($options['group_by3'], $options);
+ $group_by_parts = '';
+ if (isset($options['group_by1']))
+ $group_by_parts .= ttReportHelper::makeSingleDropdownGroupByPart($options['group_by1'], $options);
+ if (isset($options['group_by2']))
+ $group_by_parts .= ttReportHelper::makeSingleDropdownGroupByPart($options['group_by2'], $options);
+ if (isset($options['group_by3']))
+ $group_by_parts .= ttReportHelper::makeSingleDropdownGroupByPart($options['group_by3'], $options);
// Remove garbage from the beginning.
$group_by_parts = ltrim($group_by_parts, ', ');
$group_by_part = "group by $group_by_parts";
@@ -1702,6 +2153,7 @@ static function makeSingleDropdownGroupByExpensesPart($dropdown_value, $options)
static function makeGroupByExpensesPart($options) {
if (!ttReportHelper::grouping($options)) return null;
+ $group_by_parts = '';
$group_by_parts .= ttReportHelper::makeSingleDropdownGroupByExpensesPart($options['group_by1'], $options);
$group_by_parts .= ttReportHelper::makeSingleDropdownGroupByExpensesPart($options['group_by2'], $options);
$group_by_parts .= ttReportHelper::makeSingleDropdownGroupByExpensesPart($options['group_by3'], $options);
@@ -1750,6 +2202,19 @@ static function makeSingleDropdownConcatCustomFieldPart($dropdown_value) {
}
}
}
+ // Iterate through project custom fields.
+ if ($custom_fields && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ if ($dropdown_value == $field_name) {
+ if ($projectField['type'] == CustomFields::TYPE_TEXT) {
+ return (", ' - ', coalesce(ecf".$projectField['id'].".value, 'Null')");
+ } elseif ($projectField['type'] == CustomFields::TYPE_DROPDOWN) {
+ return (", ' - ', coalesce(cfo".$projectField['id'].".value, 'Null')");
+ }
+ }
+ }
+ }
// Iterate through time custom fields.
if ($custom_fields && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
@@ -1784,6 +2249,19 @@ static function makeSingleDropdownConcatCustomFieldExpensesPart($dropdown_value)
}
}
}
+ // Iterate through project custom fields.
+ if ($custom_fields && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ if ($dropdown_value == $field_name) {
+ if ($projectField['type'] == CustomFields::TYPE_TEXT) {
+ return (", ' - ', coalesce(ecf".$projectField['id'].".value, 'Null')");
+ } elseif ($projectField['type'] == CustomFields::TYPE_DROPDOWN) {
+ return (", ' - ', coalesce(cfo".$projectField['id'].".value, 'Null')");
+ }
+ }
+ }
+ }
// Iterate through time custom fields.
if ($custom_fields && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
@@ -1837,6 +2315,19 @@ static function makeSingleDropdownGroupByCustomFieldPart($dropdown_value) {
}
}
}
+ // Iterate through project custom fields.
+ if ($custom_fields && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ if ($dropdown_value == $field_name) {
+ if ($projectField['type'] == CustomFields::TYPE_TEXT) {
+ return (", ecf".$projectField['id'].".value as $field_name");
+ } elseif ($projectField['type'] == CustomFields::TYPE_DROPDOWN) {
+ return (", cfo".$projectField['id'].".value as $field_name");
+ }
+ }
+ }
+ }
// Iterate through time custom fields.
if ($custom_fields && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
@@ -1871,6 +2362,19 @@ static function makeSingleDropdownGroupByCustomFieldExpensesPart($dropdown_value
}
}
}
+ // Iterate through project custom fields.
+ if ($custom_fields && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ if ($dropdown_value == $field_name) {
+ if ($projectField['type'] == CustomFields::TYPE_TEXT) {
+ return (", ecf".$projectField['id'].".value as $field_name");
+ } elseif ($projectField['type'] == CustomFields::TYPE_DROPDOWN) {
+ return (", cfo".$projectField['id'].".value as $field_name");
+ }
+ }
+ }
+ }
// Iterate through time custom fields.
if ($custom_fields && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
@@ -1888,9 +2392,13 @@ static function makeSingleDropdownGroupByCustomFieldExpensesPart($dropdown_value
static function makeGroupByFieldsPart($options) {
if (!ttReportHelper::grouping($options)) return null;
- $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldPart($options['group_by1'], $options);
- $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldPart($options['group_by2'], $options);
- $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldPart($options['group_by3'], $options);
+ $group_by_fields_parts = '';
+ if (isset($options['group_by1']))
+ $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldPart($options['group_by1'], $options);
+ if (isset($options['group_by2']))
+ $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldPart($options['group_by2'], $options);
+ if (isset($options['group_by3']))
+ $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldPart($options['group_by3'], $options);
return $group_by_fields_parts;
}
@@ -1899,9 +2407,13 @@ static function makeGroupByFieldsPart($options) {
static function makeGroupByFieldsExpensesPart($options) {
if (!ttReportHelper::grouping($options)) return null;
- $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldExpensesPart($options['group_by1'], $options);
- $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldExpensesPart($options['group_by2'], $options);
- $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldExpensesPart($options['group_by3'], $options);
+ $group_by_fields_parts = '';
+ if (isset($options['group_by1']))
+ $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldExpensesPart($options['group_by1'], $options);
+ if (isset($options['group_by2']))
+ $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldExpensesPart($options['group_by2'], $options);
+ if (isset($options['group_by3']))
+ $group_by_fields_parts .= ttReportHelper::makeSingleDropdownGroupByFieldExpensesPart($options['group_by3'], $options);
return $group_by_fields_parts;
}
@@ -1909,9 +2421,13 @@ static function makeGroupByFieldsExpensesPart($options) {
static function makeConcatPart($options) {
if (!ttReportHelper::grouping($options)) return null;
- $concat_part .= ttReportHelper::makeSingleDropdownConcatPart($options['group_by1'], $options);
- $concat_part .= ttReportHelper::makeSingleDropdownConcatPart($options['group_by2'], $options);
- $concat_part .= ttReportHelper::makeSingleDropdownConcatPart($options['group_by3'], $options);
+ $concat_part = '';
+ if (isset($options['group_by1']))
+ $concat_part .= ttReportHelper::makeSingleDropdownConcatPart($options['group_by1'], $options);
+ if (isset($options['group_by2']))
+ $concat_part .= ttReportHelper::makeSingleDropdownConcatPart($options['group_by2'], $options);
+ if (isset($options['group_by3']))
+ $concat_part .= ttReportHelper::makeSingleDropdownConcatPart($options['group_by3'], $options);
// Remove garbage from the beginning.
if (ttStartsWith($concat_part, ", ' - ', "))
$concat_part = substr($concat_part, 9);
@@ -1944,6 +2460,7 @@ static function makeSingleDropdownConcatExpensesPart($dropdown_value, $options)
static function makeConcatExpensesPart($options) {
if (!ttReportHelper::grouping($options)) return null;
+ $concat_part = '';
$concat_part .= ttReportHelper::makeSingleDropdownConcatExpensesPart($options['group_by1'], $options);
$concat_part .= ttReportHelper::makeSingleDropdownConcatExpensesPart($options['group_by2'], $options);
$concat_part .= ttReportHelper::makeSingleDropdownConcatExpensesPart($options['group_by3'], $options);
@@ -2033,7 +2550,7 @@ static function makeJoinPart($options) {
if ($user->isPluginEnabled('cf')) {
global $custom_fields;
- if (!$custom_fields) $custom_fields = new CustomFields();
+ if (!isset($custom_fields)) $custom_fields = new CustomFields();
}
$trackingMode = $user->getTrackingMode();
@@ -2050,11 +2567,11 @@ static function makeJoinPart($options) {
if (ttReportHelper::groupingBy('task', $options)) {
$left_joins .= ' left join tt_tasks t on (l.task_id = t.id)';
}
- if ($options['show_cost'] && $trackingMode != MODE_TIME) {
+ if (isset($options['show_cost']) && $options['show_cost'] && $trackingMode != MODE_TIME) {
$left_joins .= ' left join tt_user_project_binds upb on (l.user_id = upb.user_id and l.project_id = upb.project_id)';
}
// Left joins for time custom fields.
- if ($custom_fields && $custom_fields->timeFields) {
+ if (isset($custom_fields) && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
$field_name = 'time_field_'.$timeField['id'];
$field_value = $options[$field_name];
@@ -2073,7 +2590,7 @@ static function makeJoinPart($options) {
}
}
// Left joins for user custom fields.
- if ($custom_fields && $custom_fields->userFields) {
+ if (isset($custom_fields) && $custom_fields->userFields) {
foreach ($custom_fields->userFields as $userField) {
$field_name = 'user_field_'.$userField['id'];
$field_value = $options[$field_name];
@@ -2093,10 +2610,31 @@ static function makeJoinPart($options) {
}
}
}
+ // Left joins for project custom fields.
+ if (isset($custom_fields) && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ $field_value = $options[$field_name];
+ $entity_type = CustomFields::ENTITY_PROJECT;
+ if ($field_value || ttReportHelper::groupingBy($field_name, $options)) {
+ // We need to add left joins when input is not null.
+ $ecfTable = 'ecf'.$projectField['id'];
+ if ($projectField['type'] == CustomFields::TYPE_TEXT) {
+ // Add one join for each text field.
+ $left_joins .= " left join tt_entity_custom_fields $ecfTable on ($ecfTable.entity_type = $entity_type and $ecfTable.entity_id = l.project_id and $ecfTable.field_id = ".$projectField['id'].")";
+ } elseif ($projectField['type'] == CustomFields::TYPE_DROPDOWN) {
+ $cfoTable = 'cfo'.$projectField['id'];
+ // Add two joins for each dropdown field.
+ $left_joins .= " left join tt_entity_custom_fields $ecfTable on ($ecfTable.entity_type = $entity_type and $ecfTable.entity_id = l.project_id and $ecfTable.field_id = ".$projectField['id'].")";
+ $left_joins .= " left join tt_custom_field_options $cfoTable on ($cfoTable.field_id = $ecfTable.field_id and $cfoTable.id = $ecfTable.option_id)";
+ }
+ }
+ }
+ }
// Prepare inner joins.
$inner_joins = null;
- if ($user->isPluginEnabled('ts') && $options['timesheet']) {
+ if ($user->isPluginEnabled('ts') && isset($options['timesheet']) && $options['timesheet']) {
$timesheet_option = $options['timesheet'];
if ($timesheet_option == TIMESHEET_PENDING)
$inner_joins .= " inner join tt_timesheets ts on (l.timesheet_id = ts.id and ts.submit_status = 1 and ts.approve_status is null)";
@@ -2114,8 +2652,8 @@ static function makeJoinPart($options) {
static function makeWorkUnitPart($options) {
global $user;
- $workUnits = $options['show_work_units'];
- if ($workUnits) {
+ $work_unit_part = '';
+ if (isset($options['show_work_units']) && $options['show_work_units']) {
$unitTotalsOnly = $user->getConfigOption('unit_totals_only');
$firstUnitThreshold = $user->getConfigInt('1st_unit_threshold', 0);
$minutesInUnit = $user->getConfigInt('minutes_in_unit', 15);
@@ -2131,7 +2669,8 @@ static function makeWorkUnitPart($options) {
static function makeCostPart($options) {
global $user;
- if ($options['show_cost']) {
+ $cost_part = '';
+ if (isset($options['show_cost']) && $options['show_cost']) {
if (MODE_TIME == $user->getTrackingMode())
$cost_part = ", sum(cast(l.billable * coalesce(u.rate, 0) * time_to_sec(l.duration)/3600 as decimal(10, 2))) as cost";
else
@@ -2161,7 +2700,7 @@ static function makeJoinExpensesPart($options) {
}
// Not adding left joins for time custom fiels by design.
// Left joins for user custom fields.
- if ($custom_fields && $custom_fields->userFields) {
+ if (isset($custom_fields) && $custom_fields->userFields) {
foreach ($custom_fields->userFields as $userField) {
$field_name = 'user_field_'.$userField['id'];
$field_value = $options[$field_name];
@@ -2181,6 +2720,27 @@ static function makeJoinExpensesPart($options) {
}
}
}
+ // Left joins for project custom fields.
+ if (isset($custom_fields) && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ $field_value = $options[$field_name];
+ $entity_type = CustomFields::ENTITY_PROJECT;
+ if ($field_value || ttReportHelper::groupingBy($field_name, $options)) {
+ // We need to add left joins when input is not null.
+ $ecfTable = 'ecf'.$projectField['id'];
+ if ($projectField['type'] == CustomFields::TYPE_TEXT) {
+ // Add one join for each text field.
+ $left_joins .= " left join tt_entity_custom_fields $ecfTable on ($ecfTable.entity_type = $entity_type and $ecfTable.entity_id = ei.project_id and $ecfTable.field_id = ".$projectField['id'].")";
+ } elseif ($projectField['type'] == CustomFields::TYPE_DROPDOWN) {
+ $cfoTable = 'cfo'.$projectField['id'];
+ // Add two joins for each dropdown field.
+ $left_joins .= " left join tt_entity_custom_fields $ecfTable on ($ecfTable.entity_type = $entity_type and $ecfTable.entity_id = ei.project_id and $ecfTable.field_id = ".$projectField['id'].")";
+ $left_joins .= " left join tt_custom_field_options $cfoTable on ($cfoTable.field_id = $ecfTable.field_id and $cfoTable.id = $ecfTable.option_id)";
+ }
+ }
+ }
+ }
return $left_joins;
}
@@ -2198,7 +2758,10 @@ static function grouping($options) {
// ('date', 'user', 'project', etc.) by checking group_by1, group_by2,
// and group_by3 values passed in $options.
static function groupingBy($what, $options) {
- $grouping = ($options['group_by1'] == $what) || ($options['group_by2'] == $what) || ($options['group_by3'] == $what);
+ $grouping_by1 = isset($options['group_by1']) && $options['group_by1'] == $what;
+ $grouping_by2 = isset($options['group_by2']) && $options['group_by2'] == $what;
+ $grouping_by3 = isset($options['group_by3']) && $options['group_by3'] == $what;
+ $grouping = $grouping_by1 || $grouping_by2 || $grouping_by3;
return $grouping;
}
@@ -2210,9 +2773,11 @@ static function makeGroupByHeaderPart($dropdown_value) {
// First, try to get a label from a translation file, which is the most likely scenario
// such as grouping by date, user, project, or task.
- $key = 'label.'.$dropdown_value;
- $part = $i18n->get($key);
- if ($part) return $part;
+ if (!ttContains($dropdown_value, '_field_')) {
+ $key = 'label.'.$dropdown_value;
+ $part = $i18n->get($key);
+ if ($part) return $part;
+ }
// If label is not found in translation file, we may be grouping by a custom field.
// Obtain custom field label if so.
@@ -2235,30 +2800,40 @@ static function makeGroupByHeaderPart($dropdown_value) {
}
}
}
+ // Process project custom fields.
+ if ($custom_fields && $custom_fields->projectFields) {
+ foreach ($custom_fields->projectFields as $projectField) {
+ $field_name = 'project_field_'.$projectField['id'];
+ if ($dropdown_value == $field_name) {
+ return $projectField['label'];
+ }
+ }
+ }
// Return null if nothing is found.
return null;
}
- // makeGroupByHeader builds a column header for a totals-only report using group_by1,
- // group_by2, and group_by3 values passed in $options.
+ // makeGroupByHeader builds a column header for a totals-only report
+ // or a timesheet using group_by1, group_by2, and group_by3 values passed in $options.
static function makeGroupByHeader($options) {
$no_grouping = ($options['group_by1'] == null || $options['group_by1'] == 'no_grouping') &&
($options['group_by2'] == null || $options['group_by2'] == 'no_grouping') &&
($options['group_by3'] == null || $options['group_by3'] == 'no_grouping');
if ($no_grouping) return null;
- if ($options['group_by1'] != null && $options['group_by1'] != 'no_grouping') {
+ $group_by_header = '';
+ if (isset($options['group_by1']) && $options['group_by1'] != 'no_grouping') {
// We have group_by1.
$group_by1 = $options['group_by1'];
$group_by_header .= ' - '.ttReportHelper::makeGroupByHeaderPart($group_by1);
}
- if ($options['group_by2'] != null && $options['group_by2'] != 'no_grouping') {
+ if (isset($options['group_by2']) && $options['group_by2'] != 'no_grouping') {
// We have group_by2.
$group_by2 = $options['group_by2'];
$group_by_header .= ' - '.ttReportHelper::makeGroupByHeaderPart($group_by2);
}
- if ($options['group_by3'] != null && $options['group_by3'] != 'no_grouping') {
+ if (isset($options['group_by3']) && $options['group_by3'] != 'no_grouping') {
// We have group_by3.
$group_by3 = $options['group_by3'];
$group_by_header .= ' - '.ttReportHelper::makeGroupByHeaderPart($group_by3);
@@ -2270,6 +2845,14 @@ static function makeGroupByHeader($options) {
// makeGroupByXmlTag creates an xml tag for a totals only report using group_by1,
// group_by2, and group_by3 values passed in $options.
static function makeGroupByXmlTag($options) {
+ // Note: there is a problem with this function for custom fields.
+ // Returned xml tags are like "project_field_1134" and not their user entered labels.
+ // This is on purpose because we are trying to avoid potential XML parsing problems.
+ // See https://stackoverflow.com/questions/1478486/using-in-xml-element-name
+ // Perhaps review this if someone complains, but there are W3C standard (section 2.3) rules
+ // on names (including starting character).
+
+ $tag = '';
if ($options['group_by1'] != null && $options['group_by1'] != 'no_grouping') {
// We have group_by1.
$tag .= '_'.$options['group_by1'];
diff --git a/WEB-INF/lib/ttRoleHelper.class.php b/WEB-INF/lib/ttRoleHelper.class.php
index 7fa9f8fb2..fa6739a5b 100644
--- a/WEB-INF/lib/ttRoleHelper.class.php
+++ b/WEB-INF/lib/ttRoleHelper.class.php
@@ -1,30 +1,6 @@
fetchRow();
- if ($val['id'])
+ if (isset($val['id']) && $val['id'])
return $val;
}
return false;
@@ -115,7 +91,7 @@ static function getRoleByRank($rank) {
if (!is_a($res, 'PEAR_Error')) {
$val = $res->fetchRow();
- if ($val['id'])
+ if (isset($val['id']) && $val['id'])
return $val['id'];
}
return false;
@@ -130,6 +106,7 @@ static function update($fields) {
$org_id = $user->org_id;
$id = (int)$fields['id'];
+ $name_part = $rank_part = $descr_part = $status_part = $rights_part = '';
if (isset($fields['name'])) $name_part = 'name = '.$mdb2->quote($fields['name']);
if (isset($fields['rank'])) $rank_part = ', `rank` = '.(int)$fields['rank'];
if (isset($fields['description'])) $descr_part = ', description = '.$mdb2->quote($fields['description']);
@@ -149,7 +126,7 @@ static function delete($role_id) {
$group_id = $user->getGroup();
$org_id = $user->org_id;
- // Mark the task as deleted.
+ // Mark the role as deleted.
$sql = "update tt_roles set status = NULL where id = $role_id and group_id = $group_id and org_id = $org_id";
$affected = $mdb2->exec($sql);
return (!is_a($affected, 'PEAR_Error'));
@@ -191,8 +168,8 @@ static function createPredefinedRoles($group_id, $lang)
$rights_client = 'view_client_reports,view_client_invoices,manage_own_settings';
$rights_user = 'track_own_time,track_own_expenses,view_own_reports,view_own_charts,view_own_projects,view_own_tasks,manage_own_settings,view_users';
- $rights_supervisor = $rights_user.',track_time,track_expenses,view_reports,approve_reports,approve_timesheets,view_charts,view_own_clients,override_punch_mode,override_date_lock,override_own_date_lock,swap_roles,update_work';
- $rights_comanager = $rights_supervisor.',manage_own_account,manage_users,manage_projects,manage_tasks,manage_custom_fields,manage_clients,manage_invoices,override_allow_ip,manage_basic_settings,view_all_reports,manage_work,bid_on_work';
+ $rights_supervisor = $rights_user.',track_time,track_expenses,view_reports,approve_reports,approve_timesheets,view_charts,view_own_clients,override_punch_mode,override_date_lock,override_own_date_lock,swap_roles';
+ $rights_comanager = $rights_supervisor.',manage_own_account,manage_users,manage_projects,manage_tasks,manage_custom_fields,manage_clients,manage_invoices,override_allow_ip,manage_basic_settings,view_all_charts,view_all_reports';
$rights_manager = $rights_comanager.',manage_features,manage_advanced_settings,manage_roles,export_data,approve_all_reports,approve_own_timesheets,manage_subgroups';
// Active roles.
diff --git a/WEB-INF/lib/ttTaskHelper.class.php b/WEB-INF/lib/ttTaskHelper.class.php
index 015674067..e93d3d669 100644
--- a/WEB-INF/lib/ttTaskHelper.class.php
+++ b/WEB-INF/lib/ttTaskHelper.class.php
@@ -1,30 +1,6 @@
fetchRow();
- if ($val['id'])
+ if (isset($val['id']) && $val['id'])
return $val;
}
return false;
@@ -131,7 +107,14 @@ static function delete($task_id) {
// Mark the task as deleted.
$sql = "update tt_tasks set status = NULL where id = $task_id";
$affected = $mdb2->exec($sql);
- return (!is_a($affected, 'PEAR_Error'));
+ if (is_a($affected, 'PEAR_Error'))
+ return false;
+
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
+
+ return true;
}
// insert function inserts a new task into database.
@@ -185,6 +168,11 @@ static function insert($fields)
return false;
}
}
+
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
+
return $last_id;
}
@@ -266,6 +254,11 @@ static function update($fields)
}
}
}
+
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
+
return true;
}
diff --git a/WEB-INF/lib/ttTeamHelper.class.php b/WEB-INF/lib/ttTeamHelper.class.php
index 9bb538912..e12c2575b 100644
--- a/WEB-INF/lib/ttTeamHelper.class.php
+++ b/WEB-INF/lib/ttTeamHelper.class.php
@@ -1,33 +1,8 @@
query($sql);
$result = array();
if (!is_a($res, 'PEAR_Error')) {
- $dt = new DateAndTime(DB_DATEFORMAT);
while ($val = $res->fetchRow()) {
$result[] = $val;
}
diff --git a/WEB-INF/lib/ttTemplateHelper.class.php b/WEB-INF/lib/ttTemplateHelper.class.php
index cedda1671..0b9fcf92a 100644
--- a/WEB-INF/lib/ttTemplateHelper.class.php
+++ b/WEB-INF/lib/ttTemplateHelper.class.php
@@ -1,31 +1,6 @@
quote($_SERVER['REMOTE_ADDR']).', modified_by = '.$user->id;
$status = (int) $fields['status'];
- $projects = $fields['projects'];
+ $projects = isset($fields['projects']) ? $fields['projects'] : array();
$sql = "update tt_templates set name = ".$mdb2->quote($name).
", description = ".$mdb2->quote($description).
@@ -154,6 +138,10 @@ static function update($fields) {
die($affected->getMessage());
}
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
+
return true;
}
diff --git a/WEB-INF/lib/ttTimeHelper.class.php b/WEB-INF/lib/ttTimeHelper.class.php
index faa1197cd..6019b2f12 100644
--- a/WEB-INF/lib/ttTimeHelper.class.php
+++ b/WEB-INF/lib/ttTimeHelper.class.php
@@ -1,32 +1,6 @@
org_id;
$date = $fields['date'];
- $start = $fields['start'];
- $finish = $fields['finish'];
- $duration = $fields['duration'];
+ $start = isset($fields['start']) ? $fields['start'] : null;
+ $finish = isset($fields['finish']) ? $fields['finish'] : null ;
+ $duration = isset($fields['duration']) ? $fields['duration'] : null;
if ($duration) {
$minutes = ttTimeHelper::postedDurationToMinutes($duration);
$duration = ttTimeHelper::minutesToDuration($minutes);
@@ -448,10 +425,10 @@ static function insert($fields)
$client = $fields['client'];
$project = $fields['project'];
$task = $fields['task'];
- $invoice = $fields['invoice'];
+ $invoice = isset($fields['invoice']) ? $fields['invoice'] : null;
$note = $fields['note'];
$billable = $fields['billable'];
- $paid = $fields['paid'];
+ $paid = isset($fields['paid']) ? $fields['paid'] : null;
$start = ttTimeHelper::to24HourFormat($start);
if ($finish) {
@@ -463,8 +440,7 @@ static function insert($fields)
if (!$billable) $billable = 0;
if (!$paid) $paid = 0;
-
- if ($duration) {
+ if (!is_null($duration)) {
$sql = "insert into tt_log (user_id, group_id, org_id, date, duration, client_id, project_id, task_id, invoice_id, comment, billable, paid, created, created_ip, created_by) ".
"values ($user_id, $group_id, $org_id, ".$mdb2->quote($date).", '$duration', ".$mdb2->quote($client).", ".$mdb2->quote($project).", ".$mdb2->quote($task).", ".$mdb2->quote($invoice).", ".$mdb2->quote($note).", $billable, $paid $created_v)";
$affected = $mdb2->exec($sql);
@@ -473,7 +449,6 @@ static function insert($fields)
} else {
$duration = ttTimeHelper::toDuration($start, $finish);
if ($duration === false) $duration = 0;
- if (!$duration && ttTimeHelper::getUncompleted($user_id)) return false;
$sql = "insert into tt_log (user_id, group_id, org_id, date, start, duration, client_id, project_id, task_id, invoice_id, comment, billable, paid, created, created_ip, created_by) ".
"values ($user_id, $group_id, $org_id, ".$mdb2->quote($date).", '$start', '$duration', ".$mdb2->quote($client).", ".$mdb2->quote($project).", ".$mdb2->quote($task).", ".$mdb2->quote($invoice).", ".$mdb2->quote($note).", $billable, $paid $created_v)";
@@ -503,7 +478,7 @@ static function update($fields)
$task = $fields['task'];
$start = $fields['start'];
$finish = $fields['finish'];
- $duration = $fields['duration'];
+ $duration = isset($fields['duration']) ? $fields['duration'] : null;
if ($duration) {
$minutes = ttTimeHelper::postedDurationToMinutes($duration);
$duration = ttTimeHelper::minutesToDuration($minutes);
@@ -524,9 +499,9 @@ static function update($fields)
$finish = ttTimeHelper::to24HourFormat($finish);
if ('00:00' == $finish) $finish = '24:00';
- if ($start) $duration = '';
+ if ($start) $duration = null;
- if ($duration) {
+ if (!is_null($duration)) {
$sql = "UPDATE tt_log set start = NULL, duration = '$duration', client_id = ".$mdb2->quote($client).", project_id = ".$mdb2->quote($project).", task_id = ".$mdb2->quote($task).", ".
"comment = ".$mdb2->quote($note)."$billable_part $paid_part $modified_part, date = '$date' WHERE id = $id and user_id = $user_id and group_id = $group_id and org_id = $org_id";
$affected = $mdb2->exec($sql);
@@ -536,9 +511,6 @@ static function update($fields)
$duration = ttTimeHelper::toDuration($start, $finish);
if ($duration === false)
$duration = 0;
- $uncompleted = ttTimeHelper::getUncompleted($user_id);
- if (!$duration && $uncompleted && ($uncompleted['id'] != $id))
- return false;
$sql = "UPDATE tt_log SET start = '$start', duration = '$duration', client_id = ".$mdb2->quote($client).", project_id = ".$mdb2->quote($project).", task_id = ".$mdb2->quote($task).", ".
"comment = ".$mdb2->quote($note)."$billable_part $paid_part $modified_part, date = '$date' WHERE id = $id and user_id = $user_id and group_id = $group_id and org_id = $org_id";
@@ -594,7 +566,8 @@ static function getTimeForDay($date) {
$org_id = $user->org_id;
$sql = "select sum(time_to_sec(duration)) as sm from tt_log".
- " where user_id = $user_id and group_id = $group_id and org_id = $org_id and date = '$date' and status = 1";
+ " where user_id = $user_id and group_id = $group_id and org_id = $org_id".
+ " and date = ".$mdb2->quote($date)." and status = 1";
$res = $mdb2->query($sql);
if (!is_a($res, 'PEAR_Error')) {
$val = $res->fetchRow();
@@ -606,17 +579,17 @@ static function getTimeForDay($date) {
// getTimeForWeek - gets total time for a user for a given week.
static function getTimeForWeek($date) {
global $user;
- import('Period');
+ import('ttPeriod');
$mdb2 = getConnection();
$user_id = $user->getUser();
$group_id = $user->getGroup();
$org_id = $user->org_id;
- $period = new Period(INTERVAL_THIS_WEEK, $date);
+ $period = new ttPeriod($date, INTERVAL_THIS_WEEK);
$sql = "select sum(time_to_sec(duration)) as sm from tt_log".
" where user_id = $user_id and group_id = $group_id and org_id = $org_id".
- " and date >= '".$period->getStartDate(DB_DATEFORMAT)."' and date <= '".$period->getEndDate(DB_DATEFORMAT)."' and status = 1";
+ " and date >= '".$period->getStartDate()."' and date <= '".$period->getEndDate()."' and status = 1";
$res = $mdb2->query($sql);
if (!is_a($res, 'PEAR_Error')) {
$val = $res->fetchRow();
@@ -628,17 +601,17 @@ static function getTimeForWeek($date) {
// getTimeForMonth - gets total time for a user for a given month.
static function getTimeForMonth($date) {
global $user;
- import('Period');
+ import('ttPeriod');
$mdb2 = getConnection();
$user_id = $user->getUser();
$group_id = $user->getGroup();
$org_id = $user->org_id;
- $period = new Period(INTERVAL_THIS_MONTH, $date);
+ $period = new ttPeriod($date, INTERVAL_THIS_MONTH);
$sql = "select sum(time_to_sec(duration)) as sm from tt_log".
" where user_id = $user_id and group_id = $group_id and org_id = $org_id".
- " and date >= '".$period->getStartDate(DB_DATEFORMAT)."' and date <= '".$period->getEndDate(DB_DATEFORMAT)."' and status = 1";
+ " and date >= '".$period->getStartDate()."' and date <= '".$period->getEndDate()."' and status = 1";
$res = $mdb2->query($sql);
if (!is_a($res, 'PEAR_Error')) {
$val = $res->fetchRow();
@@ -649,10 +622,45 @@ static function getTimeForMonth($date) {
// getUncompleted - retrieves an uncompleted record for user, if one exists.
static function getUncompleted($user_id) {
+
+ $user_id = (int) $user_id; // Protection against sql injection.
+
+ global $user;
+ $group_id = $user->getGroup();
+ $org_id = $user->org_id;
+
$mdb2 = getConnection();
$sql = "select id, start, date from tt_log".
- " where user_id = $user_id and start is not null and time_to_sec(duration) = 0 and status = 1";
+ " where user_id = $user_id and start is not null and time_to_sec(duration) = 0 and status = 1".
+ " and group_id = $group_id and org_id = $org_id";
+ $res = $mdb2->query($sql);
+ if (!is_a($res, 'PEAR_Error')) {
+ if (!$res->numRows()) {
+ return false;
+ }
+ if ($val = $res->fetchRow()) {
+ return $val;
+ }
+ }
+ return false;
+ }
+
+ // getFirstUncompletedForDate - retrieves first found uncompleted record for user for a specific date, if one exists.
+ static function getFirstUncompletedForDate($user_id, $date) {
+
+ $user_id = (int) $user_id; // Protection against sql injection.
+
+ global $user;
+ $group_id = $user->getGroup();
+ $org_id = $user->org_id;
+
+ $mdb2 = getConnection();
+
+ $sql = "select id, start, date from tt_log".
+ " where user_id = $user_id and start is not null and time_to_sec(duration) = 0 and status = 1".
+ " and group_id = $group_id and org_id = $org_id and date = ".$mdb2->quote($date).
+ " order by start"; // Ordering by start time to get the earliest uncompleted for date.
$res = $mdb2->query($sql);
if (!is_a($res, 'PEAR_Error')) {
if (!$res->numRows()) {
@@ -716,6 +724,8 @@ static function overlaps($user_id, $date, $start, $finish, $record_id = null) {
// getRecord - retrieves a time record identified by its id.
static function getRecord($id) {
global $user;
+
+ $id = (int) $id; // Protection against sql injections.
$user_id = $user->getUser();
$group_id = $user->getGroup();
@@ -747,6 +757,44 @@ static function getRecord($id) {
return false;
}
+ // getOnBehalfRecord - retrieves a time record on behalf of user.
+ // If such record is found, it also sets on behalf user.
+ static function getOnBehalfRecord($id) {
+ global $user;
+
+ // Determine user id for record.
+ $user_id = ttTimeHelper::getUserForRecord($id);
+ $user_valid = $user->isUserValid($user_id);
+
+ if (!$user_valid) return false;
+
+ // Set on behalf user.
+ $user->setOnBehalfUser($user_id);
+ // Get on behalf record.
+ return ttTimeHelper::getRecord($id);
+ }
+
+ // getUserForRecord - retrieves user id for a time record.
+ static function getUserForRecord($id) {
+ global $user;
+
+ $group_id = $user->getGroup();
+ $org_id = $user->org_id;
+
+ $mdb2 = getConnection();
+
+ // Obtain user_id for the time record.
+ $sql = "select l.user_id from tt_log l ".
+ " where l.id = $id and l.group_id = $group_id and l.org_id = $org_id and l.status = 1";
+ $res = $mdb2->query($sql);
+ if (is_a($res, 'PEAR_Error')) return false;
+ if (!$res->numRows()) return false;
+
+ $val = $res->fetchRow();
+ $user_id = $val['user_id'];
+ return $user_id;
+ }
+
// getRecordForFileView - retrieves a time record identified by its id for
// attachment view operation.
//
@@ -867,7 +915,8 @@ static function getRecords($date, $includeFiles = false) {
$time_fields_array = array();
}
- if ($custom_fields && $custom_fields->timeFields) {
+ $time_fields = '';
+ if (isset($custom_fields) && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
$field_name = 'time_field_'.$timeField['id'];
if ($timeField['type'] == CustomFields::TYPE_TEXT) {
@@ -881,6 +930,8 @@ static function getRecords($date, $includeFiles = false) {
$time_fields = ", ".join(', ', $time_fields_array);
}
+ $filePart = '';
+ $fileJoin = '';
if ($includeFiles) {
$filePart = ', if(Sub1.entity_id is null, 0, 1) as has_files';
$fileJoin = " left join (select distinct entity_id from tt_files".
@@ -893,7 +944,7 @@ static function getRecords($date, $includeFiles = false) {
if ($user->isPluginEnabled('cl'))
$left_joins .= " left join tt_clients c on (l.client_id = c.id)";
- if ($custom_fields && $custom_fields->timeFields) {
+ if (isset($custom_fields) && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
$field_name = 'time_field_'.$timeField['id'];
$cflTable = 'cfl'.$timeField['id'];
diff --git a/WEB-INF/lib/ttTimesheetHelper.class.php b/WEB-INF/lib/ttTimesheetHelper.class.php
index 17119edac..16d740291 100644
--- a/WEB-INF/lib/ttTimesheetHelper.class.php
+++ b/WEB-INF/lib/ttTimesheetHelper.class.php
@@ -1,33 +1,11 @@
date_format, $fields['start_date']);
- $start = $start_date->toString(DB_DATEFORMAT);
+ $start_date = new ttDate($fields['start_date'], $user->getDateFormat());
+ $start = $start_date->toString();
- $end_date = new DateAndTime($user->date_format, $fields['end_date']);
- $end = $end_date->toString(DB_DATEFORMAT);
+ $end_date = new ttDate($fields['end_date'], $user->getDateFormat());
+ $end = $end_date->toString();
$created_part = ', now(), '.$mdb2->quote($_SERVER['REMOTE_ADDR']).', '.$user->id;
@@ -88,9 +66,11 @@ static function createTimesheet($fields)
$last_id = $mdb2->lastInsertID('tt_timesheets', 'id');
// Associate tt_log items with timesheet.
+ $client_id = $project_id = null;
if (isset($fields['client'])) $client_id = (int) $fields['client_id'];
if (isset($fields['project_id'])) $project_id = (int) $fields['project_id'];
// sql parts.
+ $client_part = $project_part = '';
if ($client_id) $client_part = " and client_id = $client_id";
if ($project_id) $project_part = " and project_id = $project_id";
@@ -115,6 +95,7 @@ static function getActiveTimesheets()
$group_id = $user->getGroup();
$org_id = $user->org_id;
+ $filePart = $fileJoin = '';
if ($user->isPluginEnabled('at')) {
$filePart = ', if(Sub1.entity_id is null, 0, 1) as has_files';
$fileJoin = " left join (select distinct entity_id from tt_files".
@@ -148,6 +129,7 @@ static function getInactiveTimesheets()
$group_id = $user->getGroup();
$org_id = $user->org_id;
+ $filePart = $fileJoin = '';
if ($user->isPluginEnabled('at')) {
$filePart = ', if(Sub1.entity_id is null, 0, 1) as has_files';
$fileJoin = " left join (select distinct entity_id from tt_files".
@@ -462,16 +444,18 @@ static function timesheetItemsExist($fields) {
$group_id = $user->getGroup();
$org_id = $user->org_id;
+ $client_id = $project_id = null;
if (isset($fields['client_id'])) $client_id = (int) $fields['client_id'];
if (isset($fields['project_id'])) $project_id = (int) $fields['project_id'];
- $start_date = new DateAndTime($user->date_format, $fields['start_date']);
- $start = $start_date->toString(DB_DATEFORMAT);
+ $start_date = new ttDate($fields['start_date'], $user->getDateFormat());
+ $start = $start_date->toString();
- $end_date = new DateAndTime($user->date_format, $fields['end_date']);
- $end = $end_date->toString(DB_DATEFORMAT);
+ $end_date = new ttDate($fields['end_date'], $user->getDateFormat());
+ $end = $end_date->toString();
// sql parts.
+ $client_part = $project_part = '';
if ($client_id) $client_part = " and client_id = $client_id";
if ($project_id) $project_part = " and project_id = $project_id";
@@ -500,18 +484,20 @@ static function overlaps($fields) {
$group_id = $user->getGroup();
$org_id = $user->org_id;
+ $client_id = $project_id = null;
if (isset($fields['client_id'])) $client_id = (int) $fields['client_id'];
if (isset($fields['project_id'])) $project_id = (int) $fields['project_id'];
- $start_date = new DateAndTime($user->date_format, $fields['start_date']);
- $start = $start_date->toString(DB_DATEFORMAT);
+ $start_date = new ttDate($fields['start_date'], $user->getDateFormat());
+ $start = $start_date->toString();
$quoted_start = $mdb2->quote($start);
- $end_date = new DateAndTime($user->date_format, $fields['end_date']);
- $end = $end_date->toString(DB_DATEFORMAT);
+ $end_date = new ttDate($fields['end_date'], $user->getDateFormat());
+ $end = $end_date->toString();
$quoted_end = $mdb2->quote($end);
// sql parts.
+ $client_part = $project_part = '';
if ($client_id) $client_part = " and client_id = $client_id";
if ($project_id) $project_part = " and project_id = $project_id";
@@ -523,7 +509,7 @@ static function overlaps($fields) {
$res = $mdb2->query($sql);
if (!is_a($res, 'PEAR_Error')) {
$val = $res->fetchRow();
- if ($val['id']) {
+ if (isset($val['id']) && $val['id']) {
return true;
}
}
@@ -560,16 +546,16 @@ static function getMatchingTimesheets($options) {
// Determine start and end dates.
$dateFormat = $user->getDateFormat();
- if ($options['period'])
- $period = new Period($options['period'], new DateAndTime($dateFormat));
+ if (isset($options['period']) && $options['period'])
+ $period = new ttPeriod(new ttDate(), $options['period']);
else {
- $period = new Period();
+ $period = new ttPeriod(new ttDate());
$period->setPeriod(
- new DateAndTime($dateFormat, $options['period_start']),
- new DateAndTime($dateFormat, $options['period_end']));
+ new ttDate($options['period_start'], $dateFormat),
+ new ttDate($options['period_end'], $dateFormat));
}
- $start = $period->getStartDate(DB_DATEFORMAT);
- $end = $period->getEndDate(DB_DATEFORMAT);
+ $start = $period->getStartDate();
+ $end = $period->getEndDate();
$result = false;
$sql = "select id, name from tt_timesheets".
diff --git a/WEB-INF/lib/ttUser.class.php b/WEB-INF/lib/ttUser.class.php
index c1b771a2d..fedf3dafb 100644
--- a/WEB-INF/lib/ttUser.class.php
+++ b/WEB-INF/lib/ttUser.class.php
@@ -1,30 +1,6 @@
quote($login);
- $sql .= " AND u.status = 1";
+ try {
+ $mdb2 = getConnection();
+
+ $sql = "SELECT u.id, u.login, u.name, u.group_id, u.role_id, r.rank, r.name as role_name, r.rights, u.client_id,".
+ " u.quota_percent, u.email, g.org_id, g.group_key, g.name as group_name, g.currency, g.lang, g.decimal_mark, g.date_format,".
+ " g.time_format, g.week_start, g.tracking_mode, g.project_required, g.record_type,".
+ " g.bcc_email, g.allow_ip, g.password_complexity, g.plugins, g.config, g.lock_spec, g.custom_css, g.custom_translation,".
+ " g.holidays, g.workday_minutes, g.custom_logo".
+ " FROM tt_users u LEFT JOIN tt_groups g ON (u.group_id = g.id) LEFT JOIN tt_roles r on (r.id = u.role_id) WHERE ";
+ if ($id)
+ $sql .= "u.id = $id";
+ else
+ $sql .= "u.login = ".$mdb2->quote($login);
+ $sql .= " AND u.status = 1";
+
+ $res = $mdb2->query($sql);
+ if (is_a($res, 'PEAR_Error')) {
+ return;
+ }
- $res = $mdb2->query($sql);
- if (is_a($res, 'PEAR_Error')) {
- return;
- }
+ $val = $res->fetchRow();
+ if ($val['id'] > 0) {
+ $this->login = $val['login'];
+ $this->name = $val['name'];
+ $this->id = $val['id'];
+ $this->org_id = $val['org_id'];
+ $this->group_id = $val['group_id'];
+ $this->group_key = $val['group_key'];
+ if ($this->org_id == $this->group_key) $this->org_key = $val['group_key'];
+ $this->role_id = $val['role_id'];
+ $this->role_name = $val['role_name'];
+ $this->rights = explode(',', $val['rights']);
+ $this->rank = $val['rank'];
+ $this->client_id = $val['client_id'];
+ $this->is_client = $this->client_id && !in_array('track_own_time', $this->rights);
+ if ($val['quota_percent']) $this->quota_percent = $val['quota_percent'];
+ $this->email = $val['email'];
+ if ($val['lang']) $this->lang = $val['lang'];
+ if ($val['decimal_mark']) $this->decimal_mark = $val['decimal_mark'];
+ $this->date_format = $val['date_format'];
+ $this->time_format = $val['time_format'];
+ $this->week_start = $val['week_start'];
+ $this->tracking_mode = $val['tracking_mode'];
+ $this->project_required = $val['project_required'];
+ $this->record_type = $val['record_type'];
+ $this->bcc_email = $val['bcc_email'];
+ $this->allow_ip = $val['allow_ip'];
+ $this->password_complexity = $val['password_complexity'];
+ $this->group_name = $val['group_name'];
+ $this->currency = $val['currency'];
+ $this->plugins = $val['plugins'];
+ $this->lock_spec = $val['lock_spec'];
+ $this->holidays = $val['holidays'];
+ $this->workday_minutes = $val['workday_minutes'];
+ $this->custom_logo = $val['custom_logo'];
+
+ // TODO: refactor this.
+ $this->config = $val['config'];
+ $this->configHelper = new ttConfigHelper($val['config']);
+
+ // Set user config options.
+ $this->punch_mode = $this->configHelper->getDefinedValue('punch_mode');
+ $this->allow_overlap = $this->configHelper->getDefinedValue('allow_overlap');
+
+ $this->custom_css = $val['custom_css'];
+ $this->custom_translation = $val['custom_translation'];
+
+ // Set "on behalf" id and name (user).
+ if (isset($_SESSION['behalf_id'])) {
+ $this->behalf_id = $_SESSION['behalf_id'];
+ $this->behalf_name = $_SESSION['behalf_name'];
+
+ $this->behalfUser = new ttBehalfUser($this->behalf_id, $this->org_id);
+ }
+ // Set "on behalf" id and name (group).
+ if (isset($_SESSION['behalf_group_id'])) {
+ $this->behalf_group_id = $_SESSION['behalf_group_id'];
+ $this->behalf_group_name = $_SESSION['behalf_group_name'];
- $val = $res->fetchRow();
- if ($val['id'] > 0) {
- $this->login = $val['login'];
- $this->name = $val['name'];
- $this->id = $val['id'];
- $this->org_id = $val['org_id'];
- $this->group_id = $val['group_id'];
- $this->group_key = $val['group_key'];
- if ($this->org_id == $this->group_key) $this->org_key = $val['group_key'];
- $this->role_id = $val['role_id'];
- $this->role_name = $val['role_name'];
- $this->rights = explode(',', $val['rights']);
- $this->rank = $val['rank'];
- $this->client_id = $val['client_id'];
- $this->is_client = $this->client_id && !in_array('track_own_time', $this->rights);
- if ($val['quota_percent']) $this->quota_percent = $val['quota_percent'];
- $this->email = $val['email'];
- if ($val['lang']) $this->lang = $val['lang'];
- if ($val['decimal_mark']) $this->decimal_mark = $val['decimal_mark'];
- $this->date_format = $val['date_format'];
- $this->time_format = $val['time_format'];
- $this->week_start = $val['week_start'];
- $this->tracking_mode = $val['tracking_mode'];
- $this->project_required = $val['project_required'];
- $this->record_type = $val['record_type'];
- $this->bcc_email = $val['bcc_email'];
- $this->allow_ip = $val['allow_ip'];
- $this->password_complexity = $val['password_complexity'];
- $this->group_name = $val['group_name'];
- $this->currency = $val['currency'];
- $this->plugins = $val['plugins'];
- $this->lock_spec = $val['lock_spec'];
- $this->holidays = $val['holidays'];
- $this->workday_minutes = $val['workday_minutes'];
- $this->custom_logo = $val['custom_logo'];
-
- // TODO: refactor this.
- $this->config = $val['config'];
- $this->configHelper = new ttConfigHelper($val['config']);
-
- // Set user config options.
- $this->punch_mode = $this->configHelper->getDefinedValue('punch_mode');
- $this->allow_overlap = $this->configHelper->getDefinedValue('allow_overlap');
-
- $this->custom_css = $val['custom_css'];
-
- // Set "on behalf" id and name (user).
- if (isset($_SESSION['behalf_id'])) {
- $this->behalf_id = $_SESSION['behalf_id'];
- $this->behalf_name = $_SESSION['behalf_name'];
-
- $this->behalfUser = new ttBehalfUser($this->behalf_id, $this->org_id);
+ $this->behalfGroup = new ttGroup($this->behalf_group_id, $this->org_id);
+ }
}
- // Set "on behalf" id and name (group).
- if (isset($_SESSION['behalf_group_id'])) {
- $this->behalf_group_id = $_SESSION['behalf_group_id'];
- $this->behalf_group_name = $_SESSION['behalf_group_name'];
- $this->behalfGroup = new ttGroup($this->behalf_group_id, $this->org_id);
- }
+ $this->initialized = true;
+ }
+ catch (Exception $e) {
+ error_log("Exception raised in ttUser constructor: ".$e->getMessage());
}
}
// getUser returns user id on behalf of whom the current user is operating.
function getUser() {
- return ($this->behalfUser ? $this->behalfUser->id : $this->id);
+ return (isset($this->behalfUser) ? $this->behalfUser->id : $this->id);
}
// getName returns user name on behalf of whom the current user is operating.
@@ -192,6 +182,11 @@ function getEmail() {
return ($this->behalfUser ? $this->behalfUser->email : $this->email);
}
+ // getPasswordComplexity returns password complexity for active user.
+ function getPasswordComplexity() {
+ return ($this->behalfUser ? $this->behalfUser->password_complexity : $this->password_complexity);
+ }
+
// The getGroup returns group id on behalf of which the current user is operating.
function getGroup() {
return ($this->behalfGroup ? $this->behalfGroup->id : $this->group_id);
@@ -297,8 +292,8 @@ function getConfigOption($name) {
return $config->getDefinedValue($name);
}
- // getConfigInt retruns an integer value defined in a group, or false.
- function getConfigInt($name, $defaultVal) {
+ // getConfigInt returns an integer value defined in a group, or false.
+ function getConfigInt($name, $defaultVal = 0) {
$config = new ttConfigHelper($this->getConfig());
return $config->getIntValue($name, $defaultVal);
}
@@ -308,6 +303,11 @@ function getCustomCss() {
return ($this->behalfGroup ? $this->behalfGroup->custom_css : $this->custom_css);
}
+ // getCustomTranslation returns custom translation for active group.
+ function getCustomTranslation() {
+ return ($this->behalfGroup ? $this->behalfGroup->custom_translation : $this->custom_translation);
+ }
+
// can - determines whether user has a right to do something.
function can($do_something) {
return in_array($do_something, $this->rights);
@@ -321,7 +321,7 @@ function isClient() {
// isPluginEnabled checks whether a plugin is enabled for user.
function isPluginEnabled($plugin)
{
- return in_array($plugin, explode(',', $this->getPlugins()));
+ return in_array($plugin, explode(',', $this->getPlugins() ? $this->getPlugins() : ''));
}
// isOptionEnabled checks whether a config option is enabled for user.
@@ -347,7 +347,9 @@ function getAssignedProjects($options = null)
$group_id = $this->getGroup();
$org_id = $this->org_id;
- if ($options['include_files']) {
+ $filePart = '';
+ $fileJoin = '';
+ if (isset($options['include_files']) && $options['include_files']) {
$filePart = ', if(Sub1.entity_id is null, 0, 1) as has_files';
$fileJoin = " left join (select distinct entity_id from tt_files".
" where entity_type = 'project' and group_id = $group_id and org_id = $org_id and status = 1) Sub1".
@@ -357,10 +359,10 @@ function getAssignedProjects($options = null)
// Do a query with inner join to get assigned projects.
$sql = "select p.id, p.name, p.description, p.tasks, upb.rate $filePart from tt_projects p $fileJoin".
" inner join tt_user_project_binds upb on (upb.user_id = $user_id and upb.project_id = p.id and upb.status = 1)".
- " where p.group_id = $group_id and p.org_id = $org_id and p.status = 1 order by p.name";
+ " where p.group_id = $group_id and p.org_id = $org_id and p.status = 1 order by upper(p.name)";
$res = $mdb2->query($sql);
if (!is_a($res, 'PEAR_Error')) {
- $bindTemplatesWithProjects = $options['include_templates'];
+ $bindTemplatesWithProjects = isset($options['include_templates']) && $options['include_templates'];
while ($val = $res->fetchRow()) {
// If we have to include templates, get them in a separate query for each project.
// Although, theoretically, we could use mysql group_concat, but this requires grouping by, which makes
@@ -458,7 +460,7 @@ function isDateLocked($date)
// Calculate the last occurrence of a lock.
$last = tdCron::getLastOccurrence($this->getLockSpec(), time());
- $lockdate = new DateAndTime(DB_DATEFORMAT, strftime('%Y-%m-%d', $last));
+ $lockdate = new ttDate(strftime('%Y-%m-%d', $last));
if ($date->before($lockdate))
return true;
@@ -488,6 +490,7 @@ function getUsers($options) {
$includeSelf = isset($options['include_self']);
$select_part = 'select u.id, u.group_id, u.name';
+ $include_quota = false;
if (isset($options['include_login'])) {
$select_part .= ', u.login';
// Piggy-back on include_login to see if we must also include quota_percent.
@@ -574,9 +577,11 @@ function getGroupsForDropdown() {
// addGroupToDropdown is a recursive function to populate a tree of groups, used with getGroupsForDropdown().
function addGroupToDropdown(&$groups, $group_id, $subgroup_level) {
- // Add indentation markup to indicate subdirectory level.
+ $name = '';
+ // Add indentation markup to indicate a subdirectory level.
for ($i = 0; $i < $subgroup_level; $i++) {
- $name .= '🛑'; // Unicode stop sign.
+ $name .= '*';
+ // $name .= '🛑'; // Unicode stop sign. Does not display properly in Chrome 98.
}
if ($subgroup_level) $name .= ' '; // Add an extra space.
$name .= ttGroupHelper::getGroupName($group_id);
@@ -591,6 +596,7 @@ function addGroupToDropdown(&$groups, $group_id, $subgroup_level) {
// getSubgroups obtains a list of immediate subgroups.
function getSubgroups($group_id = null) {
+ $groups = array();
$mdb2 = getConnection();
if (!$group_id) $group_id = $this->getGroup();
@@ -606,22 +612,20 @@ function getSubgroups($group_id = null) {
return $groups;
}
- // getUserDetails function is used to manage users in group and returns user details.
- // At the moment, the function is used for user edits and deletes.
- function getUserDetails($user_id) {
- if (!$this->can('manage_users')) return false;
-
+ // getUserDetails function returns user details.
+ function getUserDetails($user_id) {
$mdb2 = getConnection();
$group_id = $this->getGroup();
$org_id = $this->org_id;
+ $uid = (int)$user_id;
// Determine max rank. If we are searching in on behalf group
// then rank restriction does not apply.
- $max_rank = $this->behalfGroup ? MAX_RANK : $this->rank;
+ $max_rank = $this->behalfGroup ? MAX_RANK + 1 : $this->rank;
$sql = "select u.id, u.name, u.login, u.role_id, u.client_id, u.status, u.rate, u.quota_percent, u.email from tt_users u".
" left join tt_roles r on (u.role_id = r.id)".
- " where u.id = $user_id and u.group_id = $group_id and u.org_id = $org_id and u.status is not null".
+ " where u.id = $uid and u.group_id = $group_id and u.org_id = $org_id and u.status is not null".
" and (r.rank < $max_rank or (r.rank = $max_rank and u.id = $this->id))"; // Users with lesser roles or self.
$res = $mdb2->query($sql);
if (!is_a($res, 'PEAR_Error')) {
@@ -690,10 +694,14 @@ function adjustBehalfId() {
function updateGroup($fields) {
$mdb2 = getConnection();
- $group_id = $fields['group_id'];
+ $group_id = isset($fields['group_id']) ? $fields['group_id'] : null;
if ($group_id && !$this->isGroupValid($group_id)) return false;
if (!$group_id) $group_id = $this->getGroup();
+ $name_part = $description_part = $currency_part = $lang_part = $decimal_mark_part = $date_format_part = $time_format_part =
+ $week_start_part = $tracking_mode_part = $project_required_part = $record_type_part = $bcc_email_part = $allow_ip_part =
+ $password_complexity_part = $plugins_part = $config_part = $custom_css_part = $custom_translation_part = $lock_spec_part =
+ $holidays_part = $workday_minutes_part = '';
if (isset($fields['name'])) $name_part = ', name = '.$mdb2->quote($fields['name']);
if (isset($fields['description'])) $description_part = ', description = '.$mdb2->quote($fields['description']);
if (isset($fields['currency'])) $currency_part = ', currency = '.$mdb2->quote($fields['currency']);
@@ -709,9 +717,11 @@ function updateGroup($fields) {
if (isset($fields['record_type'])) $record_type_part = ', record_type = '.(int) $fields['record_type'];
if (isset($fields['bcc_email'])) $bcc_email_part = ', bcc_email = '.$mdb2->quote($fields['bcc_email']);
if (isset($fields['allow_ip'])) $allow_ip_part = ', allow_ip = '.$mdb2->quote($fields['allow_ip']);
+ if (isset($fields['password_complexity'])) $password_complexity_part = ', password_complexity = '.$mdb2->quote($fields['password_complexity']);
if (isset($fields['plugins'])) $plugins_part = ', plugins = '.$mdb2->quote($fields['plugins']);
if (isset($fields['config'])) $config_part = ', config = '.$mdb2->quote($fields['config']);
if (isset($fields['custom_css'])) $custom_css_part = ', custom_css = '.$mdb2->quote($fields['custom_css']);
+ if (isset($fields['custom_translation'])) $custom_translation_part = ', custom_translation = '.$mdb2->quote($fields['custom_translation']);
if (isset($fields['lock_spec'])) $lock_spec_part = ', lock_spec = '.$mdb2->quote($fields['lock_spec']);
if (isset($fields['holidays'])) $holidays_part = ', holidays = '.$mdb2->quote($fields['holidays']);
if (isset($fields['workday_minutes'])) $workday_minutes_part = ', workday_minutes = '.$mdb2->quote($fields['workday_minutes']);
@@ -719,11 +729,17 @@ function updateGroup($fields) {
$parts = trim($name_part.$description_part.$currency_part.$lang_part.$decimal_mark_part.$date_format_part.
$time_format_part.$week_start_part.$tracking_mode_part.$project_required_part.$record_type_part.
- $bcc_email_part.$allow_ip_part.$plugins_part.$config_part.$custom_css_part.$lock_spec_part.$holidays_part.$workday_minutes_part.$modified_part, ',');
+ $bcc_email_part.$allow_ip_part.$password_complexity_part.$plugins_part.$config_part.$custom_css_part.
+ $custom_translation_part.$lock_spec_part.$holidays_part.$workday_minutes_part.$modified_part, ',');
$sql = "update tt_groups set $parts where id = $group_id and org_id = $this->org_id";
$affected = $mdb2->exec($sql);
- if (is_a($affected, 'PEAR_Error')) return false;
+ if (is_a($affected, 'PEAR_Error'))
+ return false;
+
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
return true;
}
@@ -755,8 +771,8 @@ function markUserDeleted($user_id) {
if (is_a($affected, 'PEAR_Error'))
return false;
- // Mark user custom fields as deleted,
- require_once('plugins/CustomFields.class.php');
+ // Mark user custom fields as deleted.
+ require_once(APP_DIR.'/plugins/CustomFields.class.php');
$entity_type = CustomFields::ENTITY_USER;
$modified_part = ', modified = now(), modified_ip = '.$mdb2->quote($_SERVER['REMOTE_ADDR']).', modified_by = '.$mdb2->quote($this->id);
$sql = "update tt_entity_custom_fields set status = null $modified_part".
@@ -773,7 +789,9 @@ function markUserDeleted($user_id) {
if (is_a($affected, 'PEAR_Error'))
return false;
-
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
return true;
}
@@ -843,7 +861,7 @@ function getUserPartForHeader() {
$user_part .= ', '.htmlspecialchars($this->behalf_group_name).'';
} else {
if ($this->group_name) // Note: we did not require group names in the past.
- $user_part .= ', '.$this->group_name;
+ $user_part .= ', '.htmlspecialchars($this->group_name);
}
return $user_part;
}
@@ -857,6 +875,7 @@ function setOnBehalfGroup($group_id) {
$this->behalf_id = null;
$this->behalf_name = null;
unset($this->behalfGroup);
+ $this->behalfGroup = null;
unset($_SESSION['behalf_group_id']);
unset($_SESSION['behalf_group_name']);
unset($_SESSION['behalf_id']);
@@ -864,6 +883,7 @@ function setOnBehalfGroup($group_id) {
// Destroy report bean if it was set in session.
$form = new Form('dummyForm');
+ global $request;
$bean = new ActionForm('reportBean', $form, $request);
if ($bean->isSaved()) {
$bean->destroyBean();
@@ -894,6 +914,7 @@ function setOnBehalfGroup($group_id) {
// setOnBehalfUser sets on behalf user both the object and the session.
function setOnBehalfUser($user_id) {
+ $uid = (int)$user_id; // In case we forgot to sanitize $user_id before getting here.
// Unset things first.
$this->behalf_id = null;
@@ -903,16 +924,16 @@ function setOnBehalfUser($user_id) {
unset($_SESSION['behalf_name']);
// No need to set if user is us.
- if ($user_id == $this->id) return;
+ if ($uid == $this->id) return;
// No need to set if user id is not valid.
- if (!$this->isUserValid($user_id)) return;
+ if (!$this->isUserValid($uid)) return;
// We are good to set on behalf user.
- $onBehalfUserName = ttUserHelper::getUserName($user_id);
- $_SESSION['behalf_id'] = $user_id;
+ $onBehalfUserName = ttUserHelper::getUserName($uid);
+ $_SESSION['behalf_id'] = $uid;
$_SESSION['behalf_name'] = $onBehalfUserName;
- $this->behalf_id = $user_id;
+ $this->behalf_id = $uid;
$this->behalf_name = $onBehalfUserName;
$this->behalfUser = new ttBehalfUser($this->behalf_id, $this->org_id);
diff --git a/WEB-INF/lib/ttUserConfig.class.php b/WEB-INF/lib/ttUserConfig.class.php
index d0907bb6d..c14430581 100644
--- a/WEB-INF/lib/ttUserConfig.class.php
+++ b/WEB-INF/lib/ttUserConfig.class.php
@@ -1,30 +1,6 @@
mdb2->quote($name));
if (!is_a($res, 'PEAR_Error')) {
$val = $res->fetchRow();
- return $val['param_value'];
+ return @$val['param_value'];
}
return false;
}
diff --git a/WEB-INF/lib/ttUserHelper.class.php b/WEB-INF/lib/ttUserHelper.class.php
index eac057304..2aeada43c 100644
--- a/WEB-INF/lib/ttUserHelper.class.php
+++ b/WEB-INF/lib/ttUserHelper.class.php
@@ -1,30 +1,6 @@
exec($sql);
+
$sql = "select user_id from tt_tmp_refs where ref = ".$mdb2->quote($ref);
$res = $mdb2->query($sql);
if (!is_a($res, 'PEAR_Error')) {
$val = $res->fetchRow();
- return $val['user_id'];
+ if ($val)
+ return $val['user_id'];
}
return false;
}
@@ -107,38 +89,38 @@ static function insert($fields, $hash = true) {
$quota_percent = str_replace(',', '.', isset($fields['quota_percent']) ? $fields['quota_percent'] : 100);
if($rate == '')
$rate = 0;
- if (array_key_exists('status', $fields)) { // Key exists and may be NULL during migration of deleted acounts.
- $status_f = ', status';
- $status_v = ', '.$mdb2->quote($fields['status']);
- }
$created_ip_v = ', '.$mdb2->quote($_SERVER['REMOTE_ADDR']);
$created_by_v = ', '.$user->id;
- $sql = "insert into tt_users (name, login, password, group_id, org_id, role_id, client_id, rate, quota_percent, email, created, created_ip, created_by $status_f) values (".
+ $sql = "insert into tt_users (name, login, password, group_id, org_id, role_id, client_id, rate, quota_percent, email, created, created_ip, created_by) values (".
$mdb2->quote($fields['name']).", ".$mdb2->quote($fields['login']).
- ", $password, $group_id, $org_id, ".$mdb2->quote($fields['role_id']).", ".$mdb2->quote($fields['client_id']).", $rate, $quota_percent, ".$mdb2->quote($email).", now() $created_ip_v $created_by_v $status_v)";
+ ", $password, $group_id, $org_id, ".$mdb2->quote($fields['role_id']).", ".$mdb2->quote($fields['client_id']).", $rate, $quota_percent, ".$mdb2->quote($email).", now() $created_ip_v $created_by_v)";
$affected = $mdb2->exec($sql);
+ if (is_a($affected, 'PEAR_Error'))
+ return false;
// Now deal with project assignment.
- if (!is_a($affected, 'PEAR_Error')) {
- $last_id = $mdb2->lastInsertID('tt_users', 'id');
- $projects = isset($fields['projects']) ? $fields['projects'] : array();
- if (count($projects) > 0) {
- // We have at least one project assigned. Insert corresponding entries in tt_user_project_binds table.
- foreach($projects as $p) {
- if(!isset($p['rate']))
- $p['rate'] = 0;
- else
- $p['rate'] = str_replace(',', '.', $p['rate']);
-
- $sql = "insert into tt_user_project_binds (project_id, user_id, group_id, org_id, rate, status)".
- " values(".$p['id'].", $last_id, $group_id, $org_id, ".$p['rate'].", 1)";
- $affected = $mdb2->exec($sql);
- }
+ $last_id = $mdb2->lastInsertID('tt_users', 'id');
+ $projects = isset($fields['projects']) ? $fields['projects'] : array();
+ if (count($projects) > 0) {
+ // We have at least one project assigned. Insert corresponding entries in tt_user_project_binds table.
+ foreach($projects as $p) {
+ if(!isset($p['rate']))
+ $p['rate'] = 0;
+ else
+ $p['rate'] = str_replace(',', '.', $p['rate']);
+
+ $sql = "insert into tt_user_project_binds (project_id, user_id, group_id, org_id, rate, status)".
+ " values(".$p['id'].", $last_id, $group_id, $org_id, ".$p['rate'].", 1)";
+ $affected = $mdb2->exec($sql);
}
- return $last_id;
}
- return false;
+
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
+
+ return $last_id;
}
// update - updates a user in database.
@@ -154,6 +136,8 @@ static function update($user_id, $fields) {
$org_id = $user->org_id;
// Prepare query parts.
+ $login_part = $pass_part = $name_part = $role_part = $client_part =
+ $rate_part = $quota_percent_part = $status_part = '';
if (isset($fields['login'])) {
$login_part = ", login = ".$mdb2->quote($fields['login']);
}
@@ -253,6 +237,11 @@ static function update($user_id, $fields) {
}
}
}
+
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
+
return true;
}
@@ -303,6 +292,10 @@ static function delete($user_id) {
if (is_a($affected, 'PEAR_Error'))
return false;
+ // Update entities_modified, too.
+ if (!ttGroupHelper::updateEntitiesModified())
+ return false;
+
return true;
}
diff --git a/WEB-INF/lib/ttWeekViewHelper.class.php b/WEB-INF/lib/ttWeekViewHelper.class.php
index aee8c8d61..cd1e4a952 100644
--- a/WEB-INF/lib/ttWeekViewHelper.class.php
+++ b/WEB-INF/lib/ttWeekViewHelper.class.php
@@ -1,30 +1,6 @@
isOptionEnabled('weekends');
$includeNotes = $user->isOptionEnabled('week_notes');
// Construct the first row for a brand new entry.
$dataArray[] = array('row_id' => null,'label' => $i18n->get('form.week.new_entry').':'); // Insert row.
// Insert empty cells with proper control ids.
- for ($i = 0; $i < 7; $i++) {
- $control_id = '0_'. $dayHeaders[$i];
- $dataArray[0][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ if ($includeWeekends) {
+ for ($i = 0; $i < 7; $i++) {
+ $control_id = '0_'. $dayHeaders[$i];
+ $dataArray[0][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ }
+ } else {
+ for ($i = 0; $i < 5; $i++) {
+ $control_id = '0_'. $dayHeaders[$i];
+ $dataArray[0][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ }
}
if ($includeNotes) {
// Construct the second row for daily comments for a brand new entry.
$dataArray[] = array('row_id' => null,'label' => $i18n->get('label.notes').':'); // Insert row.
// Insert empty cells with proper control ids.
- for ($i = 0; $i < 7; $i++) {
- $control_id = '1_'. $dayHeaders[$i];
- $dataArray[1][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ if ($includeWeekends) {
+ for ($i = 0; $i < 7; $i++) {
+ $control_id = '1_'. $dayHeaders[$i];
+ $dataArray[1][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ }
+ } else {
+ for ($i = 0; $i < 5; $i++) {
+ $control_id = '1_'. $dayHeaders[$i];
+ $dataArray[1][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ }
}
}
@@ -229,18 +220,32 @@ static function getDataForWeekView($records, $dayHeaders) {
$dataArray[] = array('row_id' => $row_id,'label' => ttWeekViewHelper::makeRowLabel($record));
$pos = ttWeekViewHelper::findRow($row_id, $dataArray);
// Insert empty cells with proper control ids.
- for ($i = 0; $i < 7; $i++) {
- $control_id = $pos.'_'. $dayHeaders[$i];
- $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ if ($includeWeekends) {
+ for ($i = 0; $i < 7; $i++) {
+ $control_id = $pos.'_'. $dayHeaders[$i];
+ $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ }
+ } else {
+ for ($i = 0; $i < 5; $i++) {
+ $control_id = $pos.'_'. $dayHeaders[$i];
+ $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ }
}
// Insert row for comments.
if ($includeNotes) {
$dataArray[] = array('row_id' => $row_id.'_notes','label' => $i18n->get('label.notes').':');
$pos++;
// Insert empty cells with proper control ids.
- for ($i = 0; $i < 7; $i++) {
- $control_id = $pos.'_'. $dayHeaders[$i];
- $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ if ($includeWeekends) {
+ for ($i = 0; $i < 7; $i++) {
+ $control_id = $pos.'_'. $dayHeaders[$i];
+ $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ }
+ } else {
+ for ($i = 0; $i < 5; $i++) {
+ $control_id = $pos.'_'. $dayHeaders[$i];
+ $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ }
}
$pos--;
}
@@ -266,23 +271,23 @@ static function prePopulateFromPastWeeks($startDate, $dayHeaders) {
global $i18n;
// First, determine past week start and end dates.
- $objDate = new DateAndTime(DB_DATEFORMAT, $startDate);
- $objDate->decDay(7);
- $pastWeekStartDate = $objDate->toString(DB_DATEFORMAT);
- $objDate->incDay(6);
- $pastWeekEndDate = $objDate->toString(DB_DATEFORMAT);
+ $objDate = new ttDate($startDate);
+ $objDate->decrementDay(7);
+ $pastWeekStartDate = $objDate->toString();
+ $objDate->incrementDay(6);
+ $pastWeekEndDate = $objDate->toString();
unset($objDate);
// Obtain past week(s) records.
$records = ttWeekViewHelper::getRecordsForInterval($pastWeekStartDate, $pastWeekEndDate);
- // Handle potential situation of no records by re-trying for up to 4 more previous weeks (after a long vacation, etc.).
+ // Handle a potential situation of no records by re-trying for up to 4 more previous weeks (after a long vacation, etc.).
if (!$records) {
for ($i = 0; $i < 4; $i++) {
- $objDate = new DateAndTime(DB_DATEFORMAT, $pastWeekStartDate);
- $objDate->decDay(7);
- $pastWeekStartDate = $objDate->toString(DB_DATEFORMAT);
- $objDate->incDay(6);
- $pastWeekEndDate = $objDate->toString(DB_DATEFORMAT);
+ $objDate = new ttDate($pastWeekStartDate);
+ $objDate->decrementDay(7);
+ $pastWeekStartDate = $objDate->toString();
+ $objDate->incrementDay(6);
+ $pastWeekEndDate = $objDate->toString();
unset($objDate);
$records = ttWeekViewHelper::getRecordsForInterval($pastWeekStartDate, $pastWeekEndDate);
@@ -291,21 +296,38 @@ static function prePopulateFromPastWeeks($startDate, $dayHeaders) {
}
}
+ // We will need this for iterations below.
+ $includeWeekends = $user->isOptionEnabled('weekends');
+
// Construct the first row for a brand new entry.
$dataArray[] = array('row_id' => null,'label' => $i18n->get('form.week.new_entry').':'); // Insert row.
// Insert empty cells with proper control ids.
- for ($i = 0; $i < 7; $i++) {
- $control_id = '0_'. $dayHeaders[$i];
- $dataArray[0][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ if ($includeWeekends) {
+ for ($i = 0; $i < 7; $i++) {
+ $control_id = '0_'. $dayHeaders[$i];
+ $dataArray[0][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ }
+ } else {
+ for ($i = 0; $i < 5; $i++) {
+ $control_id = '0_'. $dayHeaders[$i];
+ $dataArray[0][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ }
}
$includeNotes = $user->isOptionEnabled('week_notes');
if ($includeNotes) {
// Construct the second row for daily comments for a brand new entry.
$dataArray[] = array('row_id' => null,'label' => $i18n->get('label.notes').':'); // Insert row.
// Insert empty cells with proper control ids.
- for ($i = 0; $i < 7; $i++) {
- $control_id = '1_'. $dayHeaders[$i];
- $dataArray[1][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ if ($includeWeekends) {
+ for ($i = 0; $i < 7; $i++) {
+ $control_id = '1_'. $dayHeaders[$i];
+ $dataArray[1][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ }
+ } else {
+ for ($i = 0; $i < 5; $i++) {
+ $control_id = '1_'. $dayHeaders[$i];
+ $dataArray[1][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ }
}
}
@@ -320,18 +342,32 @@ static function prePopulateFromPastWeeks($startDate, $dayHeaders) {
$dataArray[] = array('row_id' => $row_id,'label' => ttWeekViewHelper::makeRowLabel($record));
$pos = ttWeekViewHelper::findRow($row_id, $dataArray);
// Insert empty cells with proper control ids.
- for ($i = 0; $i < 7; $i++) {
- $control_id = $pos.'_'. $dayHeaders[$i];
- $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ if ($includeWeekends) {
+ for ($i = 0; $i < 7; $i++) {
+ $control_id = $pos.'_'. $dayHeaders[$i];
+ $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ }
+ } else {
+ for ($i = 0; $i < 5; $i++) {
+ $control_id = $pos.'_'. $dayHeaders[$i];
+ $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'duration' => null);
+ }
}
// Insert row for comments.
if ($includeNotes) {
$dataArray[] = array('row_id' => $row_id.'_notes','label' => $i18n->get('label.notes').':');
$pos++;
// Insert empty cells with proper control ids.
- for ($i = 0; $i < 7; $i++) {
- $control_id = $pos.'_'. $dayHeaders[$i];
- $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ if ($includeWeekends) {
+ for ($i = 0; $i < 7; $i++) {
+ $control_id = $pos.'_'. $dayHeaders[$i];
+ $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ }
+ } else {
+ for ($i = 0; $i < 5; $i++) {
+ $control_id = $pos.'_'. $dayHeaders[$i];
+ $dataArray[$pos][$dayHeaders[$i]] = array('control_id' => $control_id, 'tt_log_id' => null,'note' => null);
+ }
}
$pos--;
}
@@ -369,11 +405,13 @@ static function getDayTotals($dataArray, $dayHeaders) {
// Insert label.
global $i18n;
$dayTotals['label'] = $i18n->get('label.day_total').':';
-
+ foreach($dayHeaders as $dayHeader) {
+ $dayTotals[$dayHeader] = 0;
+ }
foreach ($dataArray as $row) {
foreach($dayHeaders as $dayHeader) {
if (array_key_exists($dayHeader, $row)) {
- $minutes = ttTimeHelper::toMinutes($row[$dayHeader]['duration']);
+ $minutes = ttTimeHelper::toMinutes(@$row[$dayHeader]['duration']);
$dayTotals[$dayHeader] += $minutes;
}
}
@@ -388,23 +426,11 @@ static function getDayTotals($dataArray, $dayHeaders) {
// getDayHeadersForWeek - obtains day column headers for week view, which are simply day numbers in month.
static function getDayHeadersForWeek($start_date) {
$dayHeaders = array();
- $objDate = new DateAndTime(DB_DATEFORMAT, $start_date);
- $dayHeaders[] = (string) $objDate->getDate(); // It returns an int on first call.
- if (strlen($dayHeaders[0]) == 1) // Which is an implementation detail of DateAndTime class.
- $dayHeaders[0] = '0'.$dayHeaders[0]; // Add a 0 for single digit day.
- $objDate->incDay();
- $dayHeaders[] = $objDate->getDate(); // After incDay it returns a string with leading 0, when necessary.
- $objDate->incDay();
- $dayHeaders[] = $objDate->getDate();
- $objDate->incDay();
- $dayHeaders[] = $objDate->getDate();
- $objDate->incDay();
- $dayHeaders[] = $objDate->getDate();
- $objDate->incDay();
- $dayHeaders[] = $objDate->getDate();
- $objDate->incDay();
- $dayHeaders[] = $objDate->getDate();
- unset($objDate);
+ $objDate = new ttDate($start_date);
+ for ($i = 0; $i < 7; $i++) {
+ $dayHeaders[] = $objDate->getDay();
+ $objDate->incrementDay();
+ }
return $dayHeaders;
}
@@ -412,12 +438,11 @@ static function getDayHeadersForWeek($start_date) {
static function getLockedDaysForWeek($start_date) {
global $user;
$lockedDays = array();
- $objDate = new DateAndTime(DB_DATEFORMAT, $start_date);
+ $objDate = new ttDate($start_date);
for ($i = 0; $i < 7; $i++) {
$lockedDays[] = $user->isDateLocked($objDate);
- $objDate->incDay();
+ $objDate->incrementDay();
}
- unset($objDate);
return $lockedDays;
}
@@ -428,8 +453,9 @@ static function getLockedDaysForWeek($start_date) {
static function makeRowIdentifier($record) {
global $user;
// Start with client.
+ $row_identifier = '';
if ($user->isPluginEnabled('cl'))
- $row_identifier = $record['client_id'] ? 'cl:'.$record['client_id'] : '';
+ $row_identifier .= $record['client_id'] ? 'cl:'.$record['client_id'] : '';
// Add billable flag.
if (!empty($row_identifier)) $row_identifier .= ',';
$row_identifier .= 'bl:'.$record['billable'];
@@ -439,7 +465,7 @@ static function makeRowIdentifier($record) {
$row_identifier .= $record['task_id'] ? ',ts:'.$record['task_id'] : '';
// Add custom field parts.
global $custom_fields;
- if ($custom_fields && $custom_fields->timeFields) {
+ if (isset($custom_fields) && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
$field_name = 'time_field_'.$timeField['id'];
if ($timeField['type'] == CustomFields::TYPE_TEXT)
@@ -460,8 +486,9 @@ static function makeRowIdentifier($record) {
static function makeRowLabel($record) {
global $user;
// Start with client.
+ $label = '';
if ($user->isPluginEnabled('cl'))
- $label = $record['client'];
+ $label .= $record['client'];
// Add project.
if (!empty($label) && !empty($record['project'])) $label .= ' - ';
@@ -473,7 +500,7 @@ static function makeRowLabel($record) {
// Add custom field parts.
global $custom_fields;
- if ($custom_fields && $custom_fields->timeFields) {
+ if (isset($custom_fields) && $custom_fields->timeFields) {
foreach ($custom_fields->timeFields as $timeField) {
$field_name = 'time_field_'.$timeField['id'];
$field_value = $record[$field_name];
@@ -513,18 +540,15 @@ static function parseFromWeekViewRow($row_id, $field_label, $base64decode = fals
// dateFromDayHeader calculates date from start date and day header in week view.
static function dateFromDayHeader($start_date, $day_header) {
- $objDate = new DateAndTime(DB_DATEFORMAT, $start_date);
- $currentDayHeader = (string) $objDate->getDate(); // It returns an int on first call.
- if (strlen($currentDayHeader) == 1) // Which is an implementation detail of DateAndTime class.
- $currentDayHeader = '0'.$currentDayHeader; // Add a 0 for single digit day.
- $i = 1;
- while ($currentDayHeader != $day_header && $i < 7) {
- // Iterate through remaining days to find a match.
- $objDate->incDay();
- $currentDayHeader = $objDate->getDate(); // After incDay it returns a string with leading 0, when necessary.
- $i++;
+ $objDate = new ttDate($start_date);
+ $currentDayHeader = $objDate->getDay();
+ for ($i = 0; $i < 7; $i++) {
+ if ($currentDayHeader == $day_header)
+ break;
+ $objDate->incrementDay();
+ $currentDayHeader = $objDate->getDay();
}
- return $objDate->toString(DB_DATEFORMAT);
+ return $objDate->toString();
}
// insertDurationFromWeekView - inserts a new record in log tables from a week view post.
@@ -534,12 +558,14 @@ static function insertDurationFromWeekView($fields, $custom_fields, $err) {
// Determine date for a new entry.
$entry_date = ttWeekViewHelper::dateFromDayHeader($fields['start_date'], $fields['day_header']);
- $objEntryDate = new DateAndTime(DB_DATEFORMAT, $entry_date);
+ $objEntryDate = new ttDate($entry_date);
// Prohibit creating entries in future.
if (!$user->isOptionEnabled('future_entries') && $fields['browser_today']) {
- $objBrowserToday = new DateAndTime(DB_DATEFORMAT, $fields['browser_today']);
- if ($objEntryDate->after($objBrowserToday)) {
+ $objBrowserToday = new ttDate($fields['browser_today']);
+ $server_tomorrow = new ttDate();
+ $server_tomorrow->incrementDay();
+ if ($objEntryDate->after($objBrowserToday) || $objEntryDate->after($server_tomorrow)) {
$err->add($i18n->get('error.future_date'));
return false;
}
@@ -553,7 +579,7 @@ static function insertDurationFromWeekView($fields, $custom_fields, $err) {
$fields4insert['billable'] = ttWeekViewHelper::parseFromWeekViewRow($fields['row_id'], 'bl');
$fields4insert['project'] = ttWeekViewHelper::parseFromWeekViewRow($fields['row_id'], 'pr');
$fields4insert['task'] = ttWeekViewHelper::parseFromWeekViewRow($fields['row_id'], 'ts');
- $fields4insert['note'] = $fields['note'];
+ $fields4insert['note'] = isset($fields['note']) ? $fields['note'] : null;
// Try to insert a record.
$id = ttTimeHelper::insert($fields4insert);
diff --git a/WEB-INF/lib/ttWorkHelper.class.php b/WEB-INF/lib/ttWorkHelper.class.php
deleted file mode 100644
index 6ddf87513..000000000
--- a/WEB-INF/lib/ttWorkHelper.class.php
+++ /dev/null
@@ -1,1617 +0,0 @@
-errors = &$errors;
-
- $this->work_server_uri = defined('WORK_SERVER_URI') ? WORK_SERVER_URI : "https://www.anuko.com/work/";
-
- // Note: at some point a need will arise for API versioning.
- // When this happens, we will append an API version number to the end of URI,
- // for example: register_0_1 instead of register.
- // This should theoretically allow a remote work server to be able to work with
- // a complete variety of deployed clients, including those without versions.
- $this->register_uri = $this->work_server_uri.'register'; // register_0_0
- $this->put_own_work_item_uri = $this->work_server_uri.'putownworkitem';
- $this->get_own_work_item_uri = $this->work_server_uri.'getownworkitem';
- $this->get_own_work_item_offer_uri = $this->work_server_uri.'getownworkitemoffer';
- $this->get_own_work_item_offers_uri = $this->work_server_uri.'getownworkitemoffers';
- $this->get_own_work_items_uri = $this->work_server_uri.'getownworkitems';
- $this->get_available_work_items_uri = $this->work_server_uri.'getavailableworkitems';
- $this->get_available_work_item_uri = $this->work_server_uri.'getavailableworkitem';
- $this->delete_own_work_item_uri = $this->work_server_uri.'deleteownworkitem';
- $this->accept_own_work_item_offer_uri = $this->work_server_uri.'acceptownworkitemoffer';
- $this->decline_own_work_item_offer_uri = $this->work_server_uri.'declineownworkitemoffer';
- $this->update_own_work_item_uri = $this->work_server_uri.'updateownworkitem';
- $this->update_own_work_item_on_offer_uri = $this->work_server_uri.'updateownworkitemonoffer';
- $this->put_own_offer_uri = $this->work_server_uri.'putownoffer';
- $this->get_own_offer_uri = $this->work_server_uri.'getownoffer';
- $this->get_own_offers_uri = $this->work_server_uri.'getownoffers';
-
- $this->get_available_offers_uri = $this->work_server_uri.'getavailableoffers';
- $this->get_available_offer_uri = $this->work_server_uri.'getavailableoffer';
- $this->get_group_items_uri = $this->work_server_uri.'getgroupitems';
- $this->delete_own_offer_uri = $this->work_server_uri.'deleteownoffer';
- $this->update_own_offer_uri = $this->work_server_uri.'updateownoffer';
- $this->send_message_to_work_owner_uri = $this->work_server_uri.'sendmessagetoworkowner';
- $this->send_message_to_offer_owner_uri = $this->work_server_uri.'sendmessagetoofferowner';
- $this->checkSiteRegistration();
- }
-
- // checkSiteRegistration - obtains site id and key from local database.
- // If not found, it tries to register with remote work server.
- function checkSiteRegistration() {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- // Obtain site id.
- $sql = "select param_value as id from tt_site_config where param_name = 'worksite_id'";
- $res = $mdb2->query($sql);
- $val = $res->fetchRow();
- if (!$val) {
- // No site id found, need to register.
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
- $fields = array('lang' => urlencode($user->lang),
- 'name' => urlencode('time tracker'),
- 'origin' => urlencode('time tracker source'),
- 'org_id' => urlencode($org_id),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'user_id' => urlencode($user->getUser()),
- 'user_name' => urlencode(base64_encode($user->getName())),
- 'user_email' => urlencode(base64_encode($user->getEmail())),
- 'user_ip' => urlencode($_SERVER['REMOTE_ADDR']));
-
- // Urlify the data for the POST.
- foreach($fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->register_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $reg_status = $result_array['reg_status']; // Registration status.
- if ($reg_status['site_id'] && $reg_status['site_key']) {
- $this->site_id = $reg_status['site_id'];
- $this->site_key = $reg_status['site_key'];
-
- // Registration successful. Store id and key locally for future use.
- $sql = "insert into tt_site_config values('worksite_id', $this->site_id, now(), null)";
- $mdb2->exec($sql);
- $sql = "insert into tt_site_config values('worksite_key', ".$mdb2->quote($this->site_key).", now(), null)";
- $mdb2->exec($sql);
- } else {
- $this->errors->add($i18n->get('error.remote_work'));
- }
- } else {
- // Site id found.
- $this->site_id = $val['id'];
-
- // Obtain site key.
- $sql = "select param_value as site_key from tt_site_config where param_name = 'worksite_key'";
- $res = $mdb2->query($sql);
- $val = $res->fetchRow();
- $this->site_key = $val['site_key'];
- }
- }
-
- // putOwnWorkItem - publishes a work item in remote work server.
- //
- // Note about some fields using additional base64 encoding.
- // There is a problem with data posted by curl calls on the server side for
- // some languages. Data arrives corrupted.
- //
- // For example: consider a case for a single Russian letter Ñ„ in the subject field.
- // UTF-8 encoding for Ñ„: 0xD1 0x84 (2 bytes).
- // urlencoded Ñ„: %D1%84 - a string of 6 characters.
- // If we use a curl call like here with only urlencoded Ñ„, what arrives on the server in POST is "C3 91 C2 84"
- // no idea what it is.
- //
- // A workaround for now is to use use an additional base64 encoding for all text fields,
- // which are decoded back to utf-8 strings on the server side.
- function putOwnWorkItem($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'group_key' => urlencode($user->getGroupKey()),
- 'offer_id' => urlencode($fields['offer_id']),
- 'type' => urlencode($fields['type']),
- 'subject' => urlencode(base64_encode($fields['subject'])),
- 'descr_short' => urlencode(base64_encode($fields['descr_short'])),
- 'descr_long' => urlencode(base64_encode($fields['descr_long'])),
- 'currency' => urlencode($fields['currency']),
- 'amount' => urlencode($fields['amount']),
- 'created_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'created_by' => urlencode($user->getUser()),
- 'created_by_name' => urlencode(base64_encode($user->getName())),
- 'created_by_email' => urlencode(base64_encode($user->getEmail()))
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->put_own_work_item_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // updateOwnWorkItem - updates a work item in remote work server.
- function updateOwnWorkItem($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'group_key' => urlencode($user->getGroupKey()),
- 'work_id' => urlencode($fields['work_id']),
- 'type' => urlencode($fields['type']),
- 'subject' => urlencode(base64_encode($fields['subject'])),
- 'descr_short' => urlencode(base64_encode($fields['descr_short'])),
- 'descr_long' => urlencode(base64_encode($fields['descr_long'])),
- 'currency' => urlencode($fields['currency']),
- 'amount' => urlencode($fields['amount']),
- 'modified_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'modified_by' => urlencode($user->getUser()),
- 'modified_by_name' => urlencode(base64_encode($user->getName())),
- 'modified_by_email' => urlencode(base64_encode($user->getEmail()))
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->update_own_work_item_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // updateOwnWorkItemOnOffer - updates own work item posted on offer in remote work server.
- function updateOwnWorkItemOnOffer($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'group_key' => urlencode($user->getGroupKey()),
- 'work_id' => urlencode($fields['work_id']),
- 'descr_short' => urlencode(base64_encode($fields['descr_short'])),
- 'descr_long' => urlencode(base64_encode($fields['descr_long'])),
- 'modified_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'modified_by' => urlencode($user->getUser()),
- 'modified_by_name' => urlencode(base64_encode($user->getName())),
- 'modified_by_email' => urlencode(base64_encode($user->getEmail()))
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->update_own_work_item_on_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // getOwnWorkItems - obtains a list of work items this group is currently outsourcing.
- function getOwnWorkItems() {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey())
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_own_work_items_iri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $active_work = $result_array['active_work'];
- return $active_work;
- }
-
- // getAvailableWorkItems - obtains a list of available work items this group can bid on.
- function getAvailableWorkItems() {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id)
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_available_work_items_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $available_work = $result_array['available_work'];
- return $available_work;
- }
-
- // getOwnWorkItem - gets work item details from remote work server.
- function getOwnWorkItem($work_id) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey()),
- 'work_id' => urlencode($work_id));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_own_work_item_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $work_item = $result_array['work_item'];
- return $work_item;
- }
-
- // getOwnWorkItemOffers - gets offers on own work item from remote work server.
- function getOwnWorkItemOffers($work_id) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey()),
- 'work_id' => urlencode($work_id));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_own_work_item_offers_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $work_item_offers = $result_array['work_item_offers'];
- return $work_item_offers;
- }
-
- // deleteOwnWorkItem - deletes work item from remote work server.
- function deleteOwnWorkItem($work_id) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey()),
- 'work_id' => urlencode($work_id),
- 'modified_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'modified_by' => urlencode($user->getUser()),
- 'modified_by_name' => urlencode(base64_encode($user->getName())),
- 'modified_by_email' => urlencode(base64_encode($user->getEmail())));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->delete_own_work_item_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // putOwnOffer - publishes an offer in remote work server.
- function putOwnOffer($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'group_key' => urlencode($user->getGroupKey()),
- 'work_id' => urlencode($fields['work_id']),
- 'subject' => urlencode(base64_encode($fields['subject'])),
- 'descr_short' => urlencode(base64_encode($fields['descr_short'])),
- 'descr_long' => urlencode(base64_encode($fields['descr_long'])),
- 'currency' => urlencode($fields['currency']),
- 'amount' => urlencode($fields['amount']),
- 'payment_info' => urlencode(base64_encode($fields['payment_info'])),
- 'created_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'created_by' => urlencode($user->getUser()),
- 'created_by_name' => urlencode(base64_encode($user->getName())),
- 'created_by_email' => urlencode(base64_encode($user->getEmail()))
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->put_own_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // getOwnOffers - obtains a list of offers this group made available to other groups.
- function getOwnOffers() {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey())
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_own_offers_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $active_offers = $result_array['active_offers'];
- return $active_offers;
- }
-
- // getAvailableOffers - obtains a list of available offers from other organizations.
- function getAvailableOffers() {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id)
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_available_offers_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $available_offers = $result_array['available_offers'];
- return $available_offers;
- }
-
- // getOwnOffer - gets offer details from remote work server.
- function getOwnOffer($offer_id) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey()),
- 'offer_id' => urlencode($offer_id));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_own_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $offer = $result_array['offer'];
- return $offer;
- }
-
- // updateOwnOffer - updates an offer in remote work server.
- function updateOwnOffer($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'group_key' => urlencode($user->getGroupKey()),
- 'offer_id' => urlencode($fields['offer_id']),
- 'subject' => urlencode(base64_encode($fields['subject'])),
- 'descr_short' => urlencode(base64_encode($fields['descr_short'])),
- 'descr_long' => urlencode(base64_encode($fields['descr_long'])),
- 'currency' => urlencode($fields['currency']),
- 'amount' => urlencode($fields['amount']),
- 'payment_info' => urlencode(base64_encode($fields['payment_info'])),
- 'modified_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'modified_by' => urlencode($user->getUser()),
- 'modified_by_name' => urlencode(base64_encode($user->getName())),
- 'modified_by_email' => urlencode(base64_encode($user->getEmail()))
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->update_own_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // deleteOwnOffer - deletes an offer from remote work server.
- function deleteOwnOffer($offer_id) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey()),
- 'offer_id' => urlencode($offer_id),
- 'modified_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'modified_by' => urlencode($user->getUser()),
- 'modified_by_name' => urlencode(base64_encode($user->getName())),
- 'modified_by_email' => urlencode(base64_encode($user->getEmail())));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->delete_own_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // getOwnWorkItemOffer - gets offer details from remote work server
- // for an offer posted on own work item.
- function getOwnWorkItemOffer($offer_id) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey()),
- 'offer_id' => urlencode($offer_id));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_own_work_item_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $offer = $result_array['offer'];
- return $offer;
- }
-
- // declineOwnWorkItemOffer - declines an offer posted on own work item in remote work server.
- function declineOwnWorkItemOffer($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey()),
- 'offer_id' => urlencode($fields['offer_id']),
- 'client_comment' => urlencode(base64_encode($fields['client_comment'])));
- //'modified_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- //'modified_by' => urlencode($user->getUser()),
- //'modified_by_name' => urlencode(base64_encode($user->getName())),
- //'modified_by_email' => urlencode(base64_encode($user->getEmail())));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->decline_own_work_item_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // acceptOwnWorkItemOffer - accepts an offer posted on own work item in remote work server.
- function acceptOwnWorkItemOffer($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey()),
- 'offer_id' => urlencode($fields['offer_id']),
- 'client_comment' => urlencode(base64_encode($fields['client_comment'])),
- 'accepted_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'accepted_by' => urlencode($user->getUser()),
- 'accepted_by_name' => urlencode(base64_encode($user->getName())),
- 'accepted_by_email' => urlencode(base64_encode($user->getEmail())));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->accept_own_work_item_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // getCurrencies - obtains a list of supported currencies.
- static function getCurrencies() {
- $mdb2 = getConnection();
-
- $sql = "select id, name from tt_work_currencies order by id";
- $res = $mdb2->query($sql);
- if (is_a($res, 'PEAR_Error')) return false;
-
- while ($val = $res->fetchRow()) {
- $result[] = array('id'=>$val['id'], 'name'=>$val['name']);
- }
- return $result;
- }
-
- // getCurrencyID - obtains an ID for currency.
- static function getCurrencyID($currency) {
- $mdb2 = getConnection();
-
- $currency_id = null;
- $sql = "select id from tt_work_currencies where name = ".$mdb2->quote($currency);
- $res = $mdb2->query($sql);
- if (is_a($res, 'PEAR_Error')) return null;
-
- if($val = $res->fetchRow()) {
- $currency_id = $val['id'];
- }
- return $currency_id;
- }
-
- // getCurrencyName - obtains currency name using its id.
- static function getCurrencyName($currency_id) {
- $mdb2 = getConnection();
-
- $currency_name = null;
- $sql = "select name from tt_work_currencies where id = $currency_id";
- $res = $mdb2->query($sql);
- if (is_a($res, 'PEAR_Error')) return null;
-
- if($val = $res->fetchRow()) {
- $currency_name = $val['name'];
- }
- return $currency_name;
- }
-
- // getGroupItems - obtains a list of all items relevant to group in one API call to Remote Work Server.
- function getGroupItems() {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_key' => urlencode($user->getGroupKey())
- );
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_group_items_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- unset($result_array['call_status']); // Remove call_status element,
- return $result_array;
- }
-
- // getAvailableWorkItem - gets available work item details from remote work server.
- function getAvailableWorkItem($work_id) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'user_id' => urlencode($user->getUser()),
- 'user_name' => urlencode(base64_encode($user->getName())),
- 'user_email' => urlencode(base64_encode($user->getEmail())),
- 'user_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'work_id' => urlencode($work_id));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_available_work_item_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $work_item = $result_array['work_item'];
- return $work_item;
- }
-
- // getAvailableOffer - gets available offer details from remote work server.
- function getAvailableOffer($offer_id) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'user_id' => urlencode($user->getUser()),
- 'user_name' => urlencode(base64_encode($user->getName())),
- 'user_email' => urlencode(base64_encode($user->getEmail())),
- 'user_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'offer_id' => urlencode($offer_id));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->get_available_offer_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- $offer = $result_array['offer'];
- return $offer;
- }
-
- // sendMessageToWorkOwner - sends a message to work owner via remote work server.
- function sendMessageToWorkOwner($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'group_key' => urlencode($user->getGroupKey()),
- 'work_id' => urlencode($fields['work_id']),
- 'sender_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'sender_user_id' => urlencode($user->getUser()),
- 'sender_name' => urlencode(base64_encode($user->getName())),
- 'sender_email' => urlencode(base64_encode($user->getEmail())),
- 'message_body' => urlencode(base64_encode($fields['message_body'])));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->send_message_to_work_owner_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-
- // sendMessageToOfferOwner - sends a message to offer owner via remote work server.
- function sendMessageToOfferOwner($fields) {
- global $i18n;
- global $user;
- $mdb2 = getConnection();
-
- $group_id = $user->getGroup();
- $org_id = $user->org_id;
-
- $curl_fields = array('lang' => urlencode($user->lang),
- 'site_id' => urlencode($this->site_id),
- 'site_key' => urlencode($this->site_key),
- 'org_id' => urlencode($org_id),
- 'org_key' => urlencode($user->getOrgKey()),
- 'group_id' => urlencode($group_id),
- 'group_name' => urlencode(base64_encode($user->getGroupName())),
- 'group_key' => urlencode($user->getGroupKey()),
- 'offer_id' => urlencode($fields['offer_id']),
- 'sender_ip' => urlencode($_SERVER['REMOTE_ADDR']),
- 'sender_user_id' => urlencode($user->getUser()),
- 'sender_name' => urlencode(base64_encode($user->getName())),
- 'sender_email' => urlencode(base64_encode($user->getEmail())),
- 'message_body' => urlencode(base64_encode($fields['message_body'])));
-
- // url-ify the data for the POST.
- foreach($curl_fields as $key=>$value) { $fields_string .= $key.'='.$value.'&'; }
- $fields_string = rtrim($fields_string, '&');
-
- // Open connection.
- $ch = curl_init();
-
- // Set the url, number of POST vars, POST data.
- curl_setopt($ch, CURLOPT_URL, $this->send_message_to_offer_owner_uri);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-
- // Execute a post request.
- $result = curl_exec($ch);
-
- // Close connection.
- curl_close($ch);
-
- if (!$result) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
-
- $result_array = json_decode($result, true);
-
- // Check for errors.
- $call_status = $result_array['call_status'];
- if (!$call_status) {
- $this->errors->add($i18n->get('error.remote_work'));
- return false;
- }
- if ($call_status['code'] != TT_CURL_SUCCESS) {
- $this->errors->add($call_status['error']);
- return false;
- }
-
- return true;
- }
-}
diff --git a/WEB-INF/resources/ca.lang.php b/WEB-INF/resources/ca.lang.php
index de6e0df96..327132ed8 100644
--- a/WEB-INF/resources/ca.lang.php
+++ b/WEB-INF/resources/ca.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Temps',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Informes',
@@ -63,7 +41,6 @@
'menu.users' => 'Usuaris',
'menu.groups' => 'Grups',
// TODO: translate the following.
-// 'menu.subgroups' => 'Subgroups',
// 'menu.export' => 'Export',
'menu.clients' => 'Clients',
'menu.options' => 'Opcions',
@@ -98,6 +75,8 @@
// 'error.record' => 'Select record.',
'error.auth' => 'Usuari o parula de pas incorrecta.',
// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
// 'error.user_exists' => 'User with this login already exists.',
// 'error.object_exists' => 'Object with this name already exists.',
// 'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -121,7 +100,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -151,9 +129,11 @@
'button.import' => 'Importar grup',
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -216,6 +196,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
// 'label.id' => 'ID',
// 'label.language' => 'Language',
// 'label.decimal_mark' => 'Decimal mark',
@@ -236,9 +217,6 @@
// 'label.ldap_hint' => 'Type your Windows login and password in the fields below.',
'label.required_fields' => '* camps requerits',
'label.on_behalf' => 'a nom de',
-'label.role_manager' => '(manejador)',
-'label.role_comanager' => '(auxiliar del manejador)',
-'label.role_admin' => '(administrador)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -264,9 +242,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Només totals',
@@ -283,20 +261,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -314,9 +280,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'Sessió iniciada',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Grups',
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'Eliminar grup',
@@ -328,6 +295,7 @@
'title.delete_time_record' => 'Eliminant l\\\'historial de temps',
// TODO: translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -413,22 +381,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -461,7 +413,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -472,13 +423,23 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => '¿Ha oblidat la seva paraula de pas?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'S\\\'ha enviat la petició de restablir paraula de pas.', // TODO: add "by email" to match the English string.
'form.reset_password.email_subject' => 'Sol·licitud de restabliment de la paraula de pas de Anuko Time Tracker',
// TODO: translate the following.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Per restablir la paraula de pas, si us plau escrigui-la i faci clic en guardar.',
@@ -514,10 +475,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Seleccionar perÃode de temps',
'form.reports.set_period' => 'o establir dates',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Mostrar camps',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Agrupar per',
'form.reports.group_by_no' => '--- no agrupar ---',
'form.reports.group_by_date' => 'data',
@@ -532,6 +496,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exportar',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -545,8 +510,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Número de factura',
'form.invoice.person' => 'Persona',
@@ -573,6 +538,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Rol',
'form.users.manager' => 'Manejador',
@@ -634,13 +600,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -649,7 +621,7 @@
'form.mail.to' => 'Per a',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'Factura enviada.',
@@ -707,21 +679,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/cs.lang.php b/WEB-INF/resources/cs.lang.php
index 92411b33b..c89457e6d 100644
--- a/WEB-INF/resources/cs.lang.php
+++ b/WEB-INF/resources/cs.lang.php
@@ -1,32 +1,9 @@
'Group',
// 'menu.plugins' => 'Plugins',
// 'menu.time' => 'Time',
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Sestavy',
@@ -64,7 +42,6 @@
'menu.users' => 'Uživatelů',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Export',
'menu.clients' => 'ZákaznÃci',
// TODO: translate the following.
@@ -100,6 +77,8 @@
// 'error.record' => 'Select record.',
'error.auth' => 'Nesprávné jméno nebo heslo.',
// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
// 'error.user_exists' => 'User with this login already exists.',
// 'error.object_exists' => 'Object with this name already exists.',
// 'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -123,7 +102,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -153,9 +131,11 @@
'button.import' => 'Importovat tým', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -224,6 +204,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Jazyk',
// TODO: translate the following.
@@ -246,10 +227,6 @@
'label.required_fields' => '* nutno vyplnit',
// TODO: translate the following.
// 'label.on_behalf' => 'on behalf of',
-'label.role_manager' => '(manažer)',
-'label.role_comanager' => '(spolumanažer)',
-'label.role_admin' => '(administrator)',
-// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
// 'label.yes' => 'yes',
@@ -274,9 +251,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Pouze souÄty',
@@ -293,20 +270,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -324,9 +289,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'Přihlásit',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Týmy', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'Smazat tým', // TODO: change "team" to "group".
@@ -338,6 +304,7 @@
'title.delete_time_record' => 'Smazat Äasový záznam',
// TODO: translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -423,22 +390,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -469,7 +420,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -480,13 +430,23 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Zapomenuté heslo?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Zaslán požadavek k vymazánà hesla.', // TODO: add "by email" to match the English string.
'form.reset_password.email_subject' => 'Anuko Time Tracker požadavek na vymazánà hesla',
// TODO: translate the following.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -523,10 +483,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Výberte obdobÃ',
'form.reports.set_period' => 'nebo urÄete dny',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Zobrazit pole',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Seskupit podle',
// TODO: translate the following.
// 'form.reports.group_by_no' => '--- no grouping ---',
@@ -541,6 +504,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exportovat',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -554,8 +518,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Faktura ÄÃslo',
'form.invoice.person' => 'Osoba',
@@ -582,6 +546,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Role',
'form.users.manager' => 'Manažer',
@@ -647,13 +612,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -662,7 +633,7 @@
'form.mail.to' => 'Komu',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'Faktura odeslána.',
@@ -720,21 +691,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/da.lang.php b/WEB-INF/resources/da.lang.php
index 3ab49c39e..6fe93c261 100644
--- a/WEB-INF/resources/da.lang.php
+++ b/WEB-INF/resources/da.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Tid',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Udgifter',
'menu.reports' => 'Rapporter',
@@ -61,7 +39,6 @@
'menu.users' => 'Brugere',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Eksport',
'menu.clients' => 'Kunder',
'menu.options' => 'Indstillinger',
@@ -90,6 +67,9 @@
// TODO: translate the following.
// 'error.record' => 'Select record.',
'error.auth' => 'Forkert brugernavn eller adgangskode.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Brugernavn eksistere allerede.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -118,7 +98,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -146,10 +125,13 @@
'button.export' => 'Eksporter team', // TODO: replace "team" with "group".
'button.import' => 'Importer team', // TODO: replace "team" with "group".
'button.close' => 'Luk',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'Stop',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -210,6 +192,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Sprog',
'label.decimal_mark' => 'Decimal tegn',
@@ -228,9 +211,6 @@
'label.ldap_hint' => 'Skriv dit Windows brugernavn eller adgangskode i felterne her under.',
'label.required_fields' => '* - obligatorisk felt',
'label.on_behalf' => 'på vegne af',
-'label.role_manager' => '(Manager)',
-'label.role_comanager' => '(Co-Manager)',
-'label.role_admin' => '(Administrator)',
'label.page' => 'Side',
'label.condition' => 'Betingelse',
// TODO: translate the following.
@@ -255,9 +235,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Kun Total',
@@ -274,21 +254,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'Aktive Brugere',
'label.inactive_users' => 'Inaktive Brugere',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -302,9 +269,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'Login',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Teams', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
'title.edit_group' => 'Redigér Team', // TODO: change "team" to "group".
'title.delete_group' => 'Slet Team', // TODO: change "team" to "group".
@@ -315,6 +283,7 @@
'title.delete_time_record' => 'Slet Tidsregistrering',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Udgifter',
'title.edit_expense' => 'Redigér Udgift',
'title.delete_expense' => 'Slet Udgift',
@@ -397,22 +366,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -445,7 +398,6 @@
'dropdown.delete' => 'Slet',
'dropdown.do_not_delete' => 'Slet ikke',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -455,15 +407,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Har du glemt din adgangskode?',
-'form.login.about' => 'Anuko Time Tracker er et nemt, let at bruge, open source tidsregistrerings system.',
+'form.login.about' => 'Anuko Time Tracker er et open source tidsregistrerings system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Nulstilling af adgangskode er sendt på email.',
'form.reset_password.email_subject' => 'Anuko Time Tracker - Anmodning om nulstilling af adgangskode',
-// TODO: English string has changed. "from IP added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate the beginning.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Hej\n\nNogen, IP %s, har bedt om at få nulstillet din adgangskode. Tryk på linket hvis du vil have nulstillet din adgangskode.\n\n%s\n\nAnuko Time Tracker er et nemt, let at bruge, open source tidsregistrerings system. Besøg https://www.anuko.com for mere information.\n\n",
+'form.reset_password.email_body' => "Hej\n\nNogen, IP %s, har bedt om at få nulstillet din adgangskode. Tryk på linket hvis du vil have nulstillet din adgangskode.\n\n%s\n\nAnuko Time Tracker er et open source tidsregistrerings system. Besøg https://www.anuko.com for mere information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Skriv en ny adgangskode og tryk Gem.',
@@ -498,10 +460,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Vælg en periode',
'form.reports.set_period' => 'eller sæt datoer',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Vis felter',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Gruppér ved',
'form.reports.group_by_no' => '--- Ingen gruppereing ---',
'form.reports.group_by_date' => 'Dato',
@@ -514,6 +479,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Eksport',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -527,8 +493,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Fakturanummer',
'form.invoice.person' => 'Person',
@@ -551,6 +517,8 @@
'form.tasks.inactive_tasks' => 'Inaktive Opgaver',
// Users form. See example at https://timetracker.anuko.com/users.php
+// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
'form.users.uncompleted_entry' => 'Bruger har en uafsluttet tidsregistrering',
'form.users.role' => 'Rolle',
'form.users.manager' => 'Manager',
@@ -611,14 +579,20 @@
'form.group_edit.type_duration' => 'Varighed',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
'form.group_edit.uncompleted_indicators' => 'Uafsluttede indikatore',
// TODO: translate the following.
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -626,7 +600,7 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Til',
'form.mail.report_subject' => 'Tidsregistrerings Rapport',
-'form.mail.footer' => 'Anuko Time Tracker er et simpelt, let at bruge, open source tidsregistrerings system. Besøg www.anuko.com for mere information.',
+'form.mail.footer' => 'Anuko Time Tracker er et open source tidsregistrerings system. Besøg www.anuko.com for mere information.',
'form.mail.report_sent' => 'Rapport sendt.',
'form.mail.invoice_sent' => 'Faktura sendt.',
@@ -683,21 +657,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/de.lang.php b/WEB-INF/resources/de.lang.php
index 7db6f93bb..9e9ad0a3d 100644
--- a/WEB-INF/resources/de.lang.php
+++ b/WEB-INF/resources/de.lang.php
@@ -1,32 +1,9 @@
'Abmelden',
'menu.forum' => 'Forum',
'menu.help' => 'Hilfe',
-// TODO: translate the following.
-// 'menu.register' => 'Register',
+'menu.register' => 'Registrieren',
'menu.profile' => 'Profil',
'menu.group' => 'Gruppe',
'menu.plugins' => 'Erweiterungen',
'menu.time' => 'Zeiten',
+'menu.puncher' => 'Stempeluhr',
'menu.week' => 'Woche',
'menu.expenses' => 'Kosten',
'menu.reports' => 'Berichte',
-// TODO: translate the following.
-// 'menu.timesheets' => 'Timesheets',
+'menu.timesheets' => 'Arbeitszeittabellen',
'menu.charts' => 'Diagramme',
'menu.projects' => 'Projekte',
'menu.tasks' => 'Aufgaben',
'menu.users' => 'Personen',
'menu.groups' => 'Gruppen',
-// TODO: translate the following.
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Exportieren',
'menu.clients' => 'Kunden',
'menu.options' => 'Optionen',
@@ -75,8 +49,7 @@
'error.access_denied' => 'Zugriff verweigert.',
'error.sys' => 'Systemfehler.',
'error.db' => 'Datenbankfehler.',
-// TODO: translate the following.
-// 'error.registered_recently' => 'Registered recently.',
+'error.registered_recently' => 'Kürzlich registriert.',
'error.feature_disabled' => 'Funktion ist deaktiviert.',
'error.field' => 'Ungültige "{0}" Daten.',
'error.empty' => 'Feld "{0}" ist leer.',
@@ -88,38 +61,34 @@
'error.report' => 'Bericht auswählen.',
'error.record' => 'Eintrag auswählen.',
'error.auth' => 'Benutzername oder Passwort ungültig.',
+'error.2fa_code' => 'Ungültiger 2FA-Code.',
+'error.weak_password' => 'Schwaches Passwort.',
'error.user_exists' => 'Benutzer mit diesem Konto ist bereits vorhanden.',
'error.object_exists' => 'Objekt mit diesem Namen ist bereits vorhanden.',
'error.invoice_exists' => 'Rechnung mit dieser Nummer existiert bereits.',
'error.role_exists' => 'Rolle mit diesem Rang existiert bereits.',
'error.no_invoiceable_items' => 'Keine Einträge zur Rechnungsstellung gefunden.',
-// TODO: translate the following.
-// 'error.no_records' => 'There are no records.',
+'error.no_records' => 'Es gibt keine Einträge.',
'error.no_login' => 'Benutzer mit diesen Anmeldedaten nicht vorhanden.',
'error.no_groups' => 'Die Datenbank ist leer. Als Administrator anmelden und ein neues Gruppe erzeugen.',
'error.upload' => 'Fehler beim hochladen einer Datei.',
-'error.range_locked' => 'Zeitinterval ist gesperrt.',
-'error.mail_send' => 'Fehler beim versenden einer E-Mail.',
-// TODO: improve the translation above by adding MAIL_SMTP_DEBUG part.
-// 'error.mail_send' => 'Error sending mail. Use MAIL_SMTP_DEBUG for diagnostics.',
+'error.range_locked' => 'Zeitintervall ist gesperrt.',
+'error.mail_send' => 'Fehler beim versenden einer E-Mail. Verwenden Sie MAIL_SMTP_DEBUG für die Diagnose.',
'error.no_email' => 'Dieser Benutzer besitzt keine e-Mail Adresse.',
'error.uncompleted_exists' => 'Unvollständiger Eintrag bereits vorhanden. Schließen oder Löschen.',
'error.goto_uncompleted' => 'Zum unvollständigen Eintrag gehen.',
-'error.overlap' => 'Der Zeitinterval überschneidet sich mit vorhandenen Einträgen.',
+'error.overlap' => 'Der Zeitintervall überschneidet sich mit vorhandenen Einträgen.',
'error.future_date' => 'Datum ist in der Zukunft.',
-// TODO: translate the following.
-// 'error.xml' => 'Error in XML file at line %d: %s.',
-// 'error.cannot_import' => 'Cannot import: %s.',
-// 'error.format' => 'Invalid file format.',
-// 'error.user_count' => 'Limit on user count.',
-// 'error.expired' => 'Expiration date reached.',
-// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
+'error.xml' => 'Fehler in der XML-Datei in der Zeile %d: %s.',
+'error.cannot_import' => 'Kann nicht importiert werden: %s.',
+'error.format' => 'Ungültiges Dateiformat.',
+'error.user_count' => 'Begrenzung der Benutzeranzahl erreicht.',
+'error.expired' => 'Ablaufdatum erreicht.',
+'error.file_storage' => 'Dateispeicherserver-Fehler.',
// Warning messages.
'warn.sure' => 'Sind Sie sicher?',
-// TODO: translate the following.
-// 'warn.confirm_save' => 'Date has changed. Confirm saving, not copying this item.',
+'warn.confirm_save' => 'Das Datum hat sich geändert. Bestätigen Sie das Speichern, nicht das Kopieren dieses Elements.',
// Success messages.
'msg.success' => 'Operation vollständig abgeschlossen.',
@@ -141,16 +110,14 @@
'button.export' => 'Gruppe exportieren',
'button.import' => 'Gruppe importieren',
'button.close' => 'Schließen',
+'button.start' => 'Start',
'button.stop' => 'Stop',
-// TODO: translate the following.
-// (PR#81 suggested 'Freigeben / Genehmigen' for 'Approve' and 'Freigabe zurücknehmen' for 'Disapprove'.
-// The problem is they do not appear precise, deviate from the meaning of approval / disaproval of report items.)
-// 'button.approve' => 'Approve', (suggested 'Freigeben / Genehmigen' does not appear precise)
-// 'button.disapprove' => 'Disapprove',
+'button.approve' => 'Annehmen',
+'button.disapprove' => 'Ablehnen',
+'button.sync' => 'Sync',
// Labels for controls on forms. Labels in this section are used on multiple forms.
-// TODO: translate the following.
-// 'label.menu' => 'Menu',
+'label.menu' => 'Menü',
'label.group_name' => 'Gruppenname',
'label.address' => 'Adresse',
'label.currency' => 'Währung',
@@ -170,9 +137,8 @@
'label.end_date' => 'Enddatum',
'label.user' => 'Benutzer',
'label.users' => 'Personen',
-// TODO: translate the following.
-// 'label.group' => 'Group',
-// 'label.subgroups' => 'Subgroups',
+'label.group' => 'Gruppe',
+'label.subgroups' => 'Untergruppen',
'label.roles' => 'Rollen',
'label.client' => 'Kunde',
'label.clients' => 'Kunden',
@@ -203,6 +169,7 @@
'label.select_none' => 'Alle abwählen',
'label.day_view' => 'Tagesansicht',
'label.week_view' => 'Wochenansicht',
+'label.puncher' => 'Stempeluhr',
'label.id' => 'ID',
'label.language' => 'Sprache',
'label.decimal_mark' => 'Dezimaltrennzeichen',
@@ -221,9 +188,6 @@
'label.ldap_hint' => 'Geben Sie unten Ihren Windows Benutzernamen und Ihr Passwort ein.',
'label.required_fields' => '* - Pflichtfelder',
'label.on_behalf' => 'für',
-'label.role_manager' => '(Manager)',
-'label.role_comanager' => '(Co-Manager)',
-'label.role_admin' => '(Administrator)',
'label.page' => 'Seite',
'label.condition' => 'Bedingung',
'label.yes' => 'Ja',
@@ -232,8 +196,7 @@
// Labels for plugins (extensions to Time Tracker that provide additional features).
'label.custom_fields' => 'Benutzerfelder',
'label.monthly_quotas' => 'Monatliche Quoten',
-// TODO: translate the following.
-// 'label.entity' => 'Entity',
+'label.entity' => 'Einheit',
'label.type' => 'Typ',
'label.type_dropdown' => 'Ausklappen',
'label.type_text' => 'Text',
@@ -246,59 +209,39 @@
'label.paid_status' => 'Bezahlstatus',
'label.paid' => 'Bezahlt',
'label.mark_paid' => 'Als bezahlt setzen',
-'label.week_menu' => 'Wochenansicht im Menü',
'label.week_note' => 'Wochennotiz',
'label.week_list' => 'Wochenliste',
+'label.weekends' => 'Wochenenden',
'label.work_units' => 'Arbeitseinheiten',
'label.work_units_short' => 'Einheiten',
'label.totals_only' => 'Nur Gesamtstunden',
'label.quota' => 'Quote',
-// TODO: translate the following.
-// 'label.timesheet' => 'Timesheet',
-// 'label.submitted' => 'Submitted',
-// 'label.approved' => 'Approved',
-// 'label.approval' => 'Report approval',
-// 'label.mark_approved' => 'Mark approved',
-// 'label.template' => 'Template',
-// 'label.bind_templates_with_projects' => 'Bind templates with projects',
-// 'label.prepopulate_note' => 'Prepopulate Note field',
-// 'label.attachments' => 'Attachments',
-// 'label.files' => 'Files',
-// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
+'label.timesheet' => 'Arbeitszeittabelle',
+'label.submitted' => 'Eingereicht',
+'label.approved' => 'Genehmigt',
+'label.approval' => 'Genehmigung des Berichts',
+'label.mark_approved' => 'Als genehmigt markieren',
+'label.template' => 'Vorlage',
+'label.bind_templates_with_projects' => 'Vorlagen mit Projekten verbinden',
+'label.prepopulate_note' => 'Notizfeld vorab ausfüllen',
+'label.attachments' => 'Anhänge',
+'label.files' => 'Dateien',
+'label.file' => 'Datei',
'label.active_users' => 'Aktive Nutzer',
'label.inactive_users' => 'Inaktive Nutzer',
-// TODO: translate the following or confirm that "Details" is also correct for German (exactly as the English string).
-// label.details is used to identify a field for LONG DESCRIPTION of a work item used in Remote Work plugin.
-// For example, a work item could be "Design a logo", and the Details hold EXACT anfd PRECISE specs of what a customer needs.
-// Another use is with offers with Remote Work plugin, where details hold a long, precise, and complete description of the offer.
-// 'label.details' => 'Details',
-'label.budget' => 'Budget',
-// TODO: translate the following.
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
-// TODO: translate the following.
-// 'entity.time' => 'time',
-// 'entity.user' => 'user',
-// 'entity.project' => 'project',
+'entity.time' => 'Zeit',
+'entity.user' => 'Benutzer',
+'entity.project' => 'Projekt',
// Form titles.
'title.error' => 'Fehler',
-'title.success' => 'Erfol',
+'title.success' => 'Erfolg',
'title.login' => 'Anmelden',
+'title.2fa' => 'Zwei-Faktor-Authentifizierung',
'title.groups' => 'Gruppen',
-// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
'title.add_group' => 'Gruppe anlegen',
'title.edit_group' => 'Gruppe bearbeiten',
'title.delete_group' => 'Gruppe löschen',
@@ -307,20 +250,18 @@
'title.time' => 'Zeiten',
'title.edit_time_record' => 'Bearbeiten des Stundeneintrags',
'title.delete_time_record' => 'Eintrag löschen',
-// TODO: Translate the following.
-// 'title.time_files' => 'Time Record Files',
+'title.time_files' => 'Zeiterfassungsdateien',
+'title.puncher' => 'Stempeluhr',
'title.expenses' => 'Kosten',
'title.edit_expense' => 'Kostenposition ändern',
'title.delete_expense' => 'Kostenposition löschen',
-// TODO: translate the following.
-// 'title.expense_files' => 'Expense Item Files',
+'title.expense_files' => 'Ausgabenartikel-Dateien',
'title.reports' => 'Berichte',
'title.report' => 'Bericht',
'title.send_report' => 'Bericht senden',
-// TODO: Translate the following.
-// 'title.timesheets' => 'Timesheets',
-// 'title.timesheet' => 'Timesheet',
-// 'title.timesheet_files' => 'Timesheet Files',
+'title.timesheets' => 'Arbeitszeittabellen',
+'title.timesheet' => 'Arbeitszeittabelle',
+'title.timesheet_files' => 'Arbeitszeittabellendateien',
'title.invoice' => 'Rechnung',
'title.send_invoice' => 'Rechnung senden',
'title.charts' => 'Diagramme',
@@ -353,10 +294,9 @@
'title.add_notification' => 'Benachrichtigung hinzufügen',
'title.edit_notification' => 'Benachrichtigung bearbeiten',
'title.delete_notification' => 'Benachrichtigung löschen',
-// TODO: translate the following.
-// 'title.add_timesheet' => 'Adding Timesheet',
-// 'title.edit_timesheet' => 'Editing Timesheet',
-// 'title.delete_timesheet' => 'Deleting Timesheet',
+'title.add_timesheet' => 'Arbeitszeittabelle hinzufügen',
+'title.edit_timesheet' => 'Arbeitszeittabelle bearbeiten',
+'title.delete_timesheet' => 'Arbeitszeittabelle löschen',
'title.monthly_quotas' => 'Monatliche Quoten',
'title.export' => 'Daten exportieren',
'title.import' => 'Daten importieren',
@@ -376,30 +316,13 @@
'title.week_view' => 'Wochenansicht',
'title.swap_roles' => 'Tausche Rollen',
'title.work_units' => 'Arbeitseinheiten',
-// TODO: translate the following.
-// 'title.templates' => 'Templates',
-// 'title.add_template' => 'Adding Template',
-// 'title.edit_template' => 'Editing Template',
-// 'title.delete_template' => 'Deleting Template',
-// 'title.edit_file' => 'Editing File',
-// 'title.delete_file' => 'Deleting File',
-// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
+'title.templates' => 'Vorlagen',
+'title.add_template' => 'Vorlage hinzufügen',
+'title.edit_template' => 'Vorlage bearbeiten',
+'title.delete_template' => 'Vorlage löschen',
+'title.edit_file' => 'Datei bearbeiten',
+'title.delete_file' => 'Datei löschen',
+'title.download_file' => 'Datei herunterladen',
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -423,21 +346,17 @@
'dropdown.clients' => 'Kunden',
'dropdown.select' => '--- auswählen ---',
'dropdown.select_invoice' => '--- Rechnung auswählen ---',
-// TODO: translate the following.
-// 'dropdown.select_timesheet' => '--- select timesheet ---',
+'dropdown.select_timesheet' => '--- Arbeitszeittabelle auswählen ---',
'dropdown.status_active' => 'aktiv',
'dropdown.status_inactive' => 'inaktiv',
'dropdown.delete' => 'löschen',
'dropdown.do_not_delete' => 'nicht löschen',
-// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
-// 'dropdown.approved' => 'approved',
-// 'dropdown.not_approved' => 'not approved',
+'dropdown.approved' => 'genehmigt',
+'dropdown.not_approved' => 'abgelehnt',
'dropdown.paid' => 'bezahlt',
'dropdown.not_paid' => 'nicht bezahlt',
-// TODO: translate the following.
-// 'dropdown.ascending' => 'ascending',
-// 'dropdown.descending' => 'descending',
+'dropdown.ascending' => 'aufsteigend',
+'dropdown.descending' => 'absteigend',
// Below is a section for strings that are used on individual forms. When a string is used only on one form it should be placed here.
// One exception is for closely related forms such as "Time" and "Editing Time Record" with similar controls. In such cases
@@ -446,12 +365,20 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Passwort vergessen?',
-'form.login.about' => 'Anuko Time Tracker ist ein einfaches, leicht zu bedienendes, Open-Source Zeiterfassungssystem.',
+'form.login.about' => 'Anuko Time Tracker ist ein Open-Source Zeiterfassungssystem.',
+
+// Email subject and body for two-factor authentication.
+'email.2fa_code.subject' => 'Anuko Time Tracker Zwei-Faktor-Authentifizierungscode',
+'email.2fa_code.body' => "Sehr geehrter Benutzer,\n\nIhr Zwei-Faktor-Authentifizierungscode lautet:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+'form.2fa.hint' => 'Überprüfen Sie Ihre E-Mails auf den 2FA-Code und geben Sie ihn hier ein.',
+'form.2fa.2fa_code' => '2FA-Code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Anfrage zur Zurücksetzung des Passwortes wurde per E-mail gesendet.',
'form.reset_password.email_subject' => 'Anuko Time Tracker Anfrage zur Zurücksetzung des Passwortes',
-'form.reset_password.email_body' => "Sehr geehrter Nutzer,\n\nEin Benutzer mit der IP %s hat vor Kurzem die Zurücksetzung Ihres Passworts für Anuko Time Tracker Passwort angefordert. Bitte rufen Sie diesen Link auf wenn Sie Ihr Passwort zurücksetzen möchten.\n\n%s\n\nAnuko Time Tracker ist ein einfaches, leicht zu bedienendes, Open-Source Zeiterfassungs-System. Besuchen Sie https://www.anuko.com für weitere Informationen.\n\n",
+'form.reset_password.email_body' => "Sehr geehrter Nutzer,\n\nEin Benutzer mit der IP %s hat vor Kurzem die Zurücksetzung Ihres Passworts für Anuko Time Tracker Passwort angefordert. Bitte rufen Sie diesen Link auf wenn Sie Ihr Passwort zurücksetzen möchten.\n\n%s\n\nAnuko Time Tracker ist ein Open-Source Zeiterfassungs-System. Besuchen Sie https://www.anuko.com für weitere Informationen.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Um das Passwort zurückzusetzen, geben Sie ein Neues ein und klicken dann auf Speichern.',
@@ -478,16 +405,14 @@
'form.reports.include_not_billable' => 'nicht in Rechnung stellen',
'form.reports.include_invoiced' => 'berechnet',
'form.reports.include_not_invoiced' => 'nicht berechnet',
-// TODO: translate the following.
-// 'form.reports.include_assigned' => 'assigned',
-// 'form.reports.include_not_assigned' => 'not assigned',
-// 'form.reports.include_pending' => 'pending',
+'form.reports.include_pending' => 'Ausstehend',
'form.reports.select_period' => 'Zeitraum auswählen',
'form.reports.set_period' => 'oder Datum eingeben',
+'form.reports.note_containing' => 'Notiz enthält',
'form.reports.show_fields' => 'Felder anzeigen',
-// TODO: translate the following.
-// 'form.reports.time_fields' => 'Time fields',
-// 'form.reports.user_fields' => 'User fields',
+'form.reports.time_fields' => 'Zeitfelder',
+'form.reports.user_fields' => 'Benutzerfelder',
+'form.reports.project_fields' => 'Projektfelder',
'form.reports.group_by' => 'Gruppieren nach',
'form.reports.group_by_no' => '--- keine Gruppierung ---',
'form.reports.group_by_date' => 'Datum',
@@ -499,22 +424,20 @@
// Report form. See example at https://timetracker.anuko.com/report.php
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exportiere',
+'form.report.per_hour' => 'Stundensatz',
'form.report.assign_to_invoice' => 'Zu Rechnung hinzufügen',
-// TODO: translate the following.
-// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
+'form.report.assign_to_timesheet' => 'Zu Arbeitszeittabelle zuweisen',
// Timesheets form. See example at https://timetracker.anuko.com/timesheets.php
-// TODO: translate the following.
-// 'form.timesheets.active_timesheets' => 'Active Timesheets',
-// 'form.timesheets.inactive_timesheets' => 'Inactive Timesheets',
+'form.timesheets.active_timesheets' => 'Aktive Arbeitszeittabellen',
+'form.timesheets.inactive_timesheets' => 'Inaktive Arbeitszeittabellen',
// Templates form. See example at https://timetracker.anuko.com/templates.php
-// TODO: translate the following.
-// 'form.templates.active_templates' => 'Active Templates',
-// 'form.templates.inactive_templates' => 'Inactive Templates',
+'form.templates.active_templates' => 'Aktive Vorlagen',
+'form.templates.inactive_templates' => 'Inaktive Vorlagen',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Rechnungsnummer',
'form.invoice.person' => 'Person',
@@ -536,6 +459,7 @@
'form.tasks.inactive_tasks' => 'Inaktive Tasks',
// Users form. See example at https://timetracker.anuko.com/users.php
+'form.users.uncompleted_entry_today' => 'Der Benutzer hat heute einen nicht abgeschlossenen Zeiteintrag',
'form.users.uncompleted_entry' => 'Nutzer hat einen unvollständigen Zeiteintrag',
'form.users.role' => 'Rolle',
'form.users.manager' => 'Manager',
@@ -589,14 +513,18 @@
'form.group_edit.type_all' => 'alle',
'form.group_edit.type_start_finish' => 'Start und Ende',
'form.group_edit.type_duration' => 'Dauer',
-'form.group_edit.punch_mode' => 'Stechuhr-Modus',
+'form.group_edit.punch_mode' => 'Stempeluhr-Modus',
+'form.group_edit.one_uncompleted' => 'Eine unvollendete',
'form.group_edit.allow_overlap' => 'Erlaube Überschneidung',
'form.group_edit.future_entries' => 'Einträge in der Zukunft',
'form.group_edit.uncompleted_indicators' => 'Zeige unfertige Einträge',
'form.group_edit.confirm_save' => 'Speichern bestätigen',
-'form.group_edit.allow_ip' => 'Erlaube IP',
-// TODO: translate the following.
-// 'form.group_edit.advanced_settings' => 'Advanced settings',
+'form.group_edit.advanced_settings' => 'Erweiterte Einstellungen',
+
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+'form.group_advanced_edit.allow_ip' => 'Erlaube IP',
+'form.group_advanced_edit.password_complexity' => 'Komplexität des Passworts',
+'form.group_advanced_edit.2fa' => 'Zwei-Faktor-Authentifizierung',
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
'form.group_delete.hint' => 'Sind Sie sicher, dass Sie die gesamte Gruppe löschen möchten?',
@@ -604,7 +532,7 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'An',
'form.mail.report_subject' => 'Time Tracker Bericht',
-'form.mail.footer' => 'Anuko Time Tracker ist ein einfaches, leicht zu bedienendes, Open-Source Zeitverwaltungs-System. Besuchen Sie www.anuko.com für weitere Informationen.',
+'form.mail.footer' => 'Anuko Time Tracker ist ein Open-Source Zeitverwaltungs-System. Besuchen Sie www.anuko.com für weitere Informationen.',
'form.mail.report_sent' => 'Der Bericht wurde gesendet.',
'form.mail.invoice_sent' => 'Die Rechnung wurde gesendet.',
@@ -612,10 +540,10 @@
'form.quota.year' => 'Jahr',
'form.quota.month' => 'Monat',
'form.quota.workday_hours' => 'Arbeitsstunden pro Tag',
-'form.quota.hint' => 'Wenn leergelassen wird die Quote automatisch berechnet (Basierend auf Arbeitsstunden pro Tag und Feiertagen)',
+'form.quota.hint' => 'Wenn leer gelassen wird die Quote automatisch berechnet (Basierend auf Arbeitsstunden pro Tag und Feiertagen)',
// Swap roles form. See example at https://timetracker.anuko.com/swap_roles.php.
-'form.swap.hint' => 'Stufen Sie ihre Rolle auf eine niedrigere indem Sie mit jemadem die Rollen tauschen. Dies kann nicht rückgängig gemacht werden.',
+'form.swap.hint' => 'Stufen Sie ihre Rolle auf eine niedrigere indem Sie mit jemandem die Rollen tauschen. Dies kann nicht rückgängig gemacht werden.',
'form.swap.swap_with' => 'Tausche Rolle mit',
// Work Units configuration form. See example at https://timetracker.anuko.com/work_units.php after enabling Work units plugin.
@@ -628,9 +556,7 @@
'role.user.description' => 'Ein normaler Benutzer ohne Administrationsrechte.',
'role.client.label' => 'Kunde',
'role.client.low_case_label' => 'Kunde',
-// TODO: translate the following.
-// 'role.client.description' => 'A client can view its own data.',
-'role.client.description' => 'Ein Kunde kann zu ihm gehörende Berichte und Rechnungen ansehen.',
+'role.client.description' => 'Ein Kunde kann seine eigenen Daten einsehen.',
'role.supervisor.label' => 'Dienstvorgesetzter',
'role.supervisor.low_case_label' => 'Dienstvorgesetzter',
'role.supervisor.description' => 'Eine Person mit ein paar Administrationsrechten.',
@@ -645,36 +571,21 @@
'role.top_manager.description' => 'Top Gruppen-Manager. Kann alles innerhalb eines Gruppenbaums administrieren',
'role.admin.label' => 'Administrator',
'role.admin.low_case_label' => 'Administrator',
-'role.admin.description' => 'Aadminsitrator der Seite.',
+'role.admin.description' => 'Administrator der Seite.',
// Timesheet View form. See example at https://timetracker.anuko.com/timesheet_view.php.
-// TODO: translate the following.
-// 'form.timesheet_view.submit_subject' => 'Timesheet approval request',
-// 'form.timesheet_view.submit_body' => "A new timesheet requires approval.User: %s.",
-// 'form.timesheet_view.approve_subject' => 'Timesheet approved',
-// 'form.timesheet_view.approve_body' => "Your timesheet %s was approved. %s",
-// 'form.timesheet_view.disapprove_subject' => 'Timesheet not approved',
-// 'form.timesheet_view.disapprove_body' => "Your timesheet %s was not approved. %s",
+'form.timesheet_view.submit_subject' => 'Antrag auf Genehmigung der Arbeitszeittabelle',
+'form.timesheet_view.submit_body' => "Eine neue Arbeitszeittabelle muss genehmigt werden. Benutzer: %s.",
+'form.timesheet_view.approve_subject' => 'Arbeitszeittabelle genehmigt',
+'form.timesheet_view.approve_body' => "Ihre Arbeitszeittabelle %s wurde genehmigt. %s",
+'form.timesheet_view.disapprove_subject' => 'Arbeitszeittabelle nicht genehmigt',
+'form.timesheet_view.disapprove_body' => "Ihre Arbeitszeittabelle %s wurde nicht genehmigt. %s",
// Display Options form. See example at https://timetracker.anuko.com/display_options.php.
'form.display_options.note_on_separate_row' => 'Beschreibung in separater Zeile',
-// TODO: translate the following.
-// 'form.display_options.not_complete_days' => 'Not complete days',
-// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+'form.display_options.not_complete_days' => 'Nicht vollständige Tage',
+'form.display_options.inactive_projects' => 'Inaktive Projekte',
+'form.display_options.cost_per_hour' => 'Kosten pro Stunde',
+'form.display_options.custom_css' => 'Benutzerdefiniertes CSS',
+'form.display_options.custom_translation' => 'Benutzerdefinierte Übersetzung',
);
diff --git a/WEB-INF/resources/en.lang.php b/WEB-INF/resources/en.lang.php
index d17ba4dc9..5858b63d4 100644
--- a/WEB-INF/resources/en.lang.php
+++ b/WEB-INF/resources/en.lang.php
@@ -1,32 +1,9 @@
'Register',
'menu.profile' => 'Profile',
'menu.group' => 'Group',
-'menu.subgroups' => 'Subgroups',
'menu.plugins' => 'Plugins',
'menu.time' => 'Time',
+'menu.puncher' => 'Punch',
'menu.week' => 'Week',
'menu.expenses' => 'Expenses',
'menu.reports' => 'Reports',
@@ -84,6 +61,8 @@
'error.report' => 'Select report.',
'error.record' => 'Select record.',
'error.auth' => 'Incorrect login or password.',
+'error.2fa_code' => 'Invalid 2FA code.',
+'error.weak_password' => 'Weak password.',
'error.user_exists' => 'User with this login already exists.',
'error.object_exists' => 'Object with this name already exists.',
'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -110,11 +89,6 @@
// "something went wrong" when trying to do some operation with attachments.
// For example, File Storage server could be offline, or Time Tracker config option is wrong, etc.
'error.file_storage' => 'File storage server error.',
-// Meaning of error.remote_work: an (unspecified) error occurred when trying to communicate with
-// "Remote Work" server, the one that supports the "Work" plugin, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// It is a generic message telling us that "something went wrong" when trying to do some operation with Work plugin.
-// For example, Remote Work server could be offline, among other things.
-'error.remote_work' => 'Remote work server error.',
// Warning messages.
'warn.sure' => 'Are you sure?',
@@ -140,9 +114,11 @@
'button.export' => 'Export group',
'button.import' => 'Import group',
'button.close' => 'Close',
+'button.start' => 'Start',
'button.stop' => 'Stop',
'button.approve' => 'Approve',
'button.disapprove' => 'Disapprove',
+'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.menu' => 'Menu',
@@ -197,6 +173,7 @@
'label.select_none' => 'Deselect all',
'label.day_view' => 'Day view',
'label.week_view' => 'Week view',
+'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Language',
'label.decimal_mark' => 'Decimal mark',
@@ -215,9 +192,6 @@
'label.ldap_hint' => 'Type your Windows login and password in the fields below.',
'label.required_fields' => '* - required fields',
'label.on_behalf' => 'on behalf of',
-'label.role_manager' => '(manager)',
-'label.role_comanager' => '(co-manager)',
-'label.role_admin' => '(administrator)',
'label.page' => 'Page',
'label.condition' => 'Condition',
'label.yes' => 'yes',
@@ -239,9 +213,9 @@
'label.paid_status' => 'Paid status',
'label.paid' => 'Paid',
'label.mark_paid' => 'Mark paid',
-'label.week_menu' => 'Week menu',
'label.week_note' => 'Week note',
'label.week_list' => 'Week list',
+'label.weekends' => 'Weekends',
'label.work_units' => 'Work units',
'label.work_units_short' => 'Units',
'label.totals_only' => 'Totals only',
@@ -257,20 +231,8 @@
'label.attachments' => 'Attachments',
'label.files' => 'Files',
'label.file' => 'File',
-'label.image' => 'Image',
-'label.download' => 'Download',
'label.active_users' => 'Active Users',
'label.inactive_users' => 'Inactive Users',
-'label.details' => 'Details',
-'label.budget' => 'Budget',
-'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -282,8 +244,8 @@
'title.error' => 'Error',
'title.success' => 'Success',
'title.login' => 'Login',
+'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Groups',
-'title.subgroups' => 'Subgroups',
'title.add_group' => 'Adding Group',
'title.edit_group' => 'Editing Group',
'title.delete_group' => 'Deleting Group',
@@ -293,6 +255,7 @@
'title.edit_time_record' => 'Editing Time Record',
'title.delete_time_record' => 'Deleting Time Record',
'title.time_files' => 'Time Record Files',
+'title.puncher' => 'Puncher',
'title.expenses' => 'Expenses',
'title.edit_expense' => 'Editing Expense Item',
'title.delete_expense' => 'Deleting Expense Item',
@@ -370,22 +333,6 @@
'title.edit_file' => 'Editing File',
'title.delete_file' => 'Deleting File',
'title.download_file' => 'Downloading File',
-'title.work' => 'Work',
-'title.add_work' => 'Adding Work',
-'title.edit_work' => 'Editing Work',
-'title.delete_work' => 'Deleting Work',
-'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-'title.available_work' => 'Available Work', // Available work items from other organizations.
-'title.inactive_work' => 'Inactive Work', // Inactive work items for group.
-'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-'title.offer' => 'Offer',
-'title.add_offer' => 'Adding Offer',
-'title.edit_offer' => 'Editing Offer',
-'title.delete_offer' => 'Deleting Offer',
-'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -414,7 +361,6 @@
'dropdown.status_inactive' => 'inactive',
'dropdown.delete' => 'delete',
'dropdown.do_not_delete' => 'do not delete',
-'dropdown.pending_approval' => 'pending approval',
'dropdown.approved' => 'approved',
'dropdown.not_approved' => 'not approved',
'dropdown.paid' => 'paid',
@@ -429,12 +375,20 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Forgot password?',
-'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Password reset request sent by email.',
'form.reset_password.email_subject' => 'Anuko Time Tracker password reset request',
-'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Type new password and click on Save.',
@@ -472,9 +426,11 @@
'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Select time period',
'form.reports.set_period' => 'or set dates',
+'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Show fields',
'form.reports.time_fields' => 'Time fields',
'form.reports.user_fields' => 'User fields',
+'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Group by',
'form.reports.group_by_no' => '--- no grouping ---',
'form.reports.group_by_date' => 'date',
@@ -486,6 +442,7 @@
// Report form. See example at https://timetracker.anuko.com/report.php
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Export',
+'form.report.per_hour' => 'Per hour',
'form.report.assign_to_invoice' => 'Assign to invoice',
'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -497,8 +454,8 @@
'form.templates.active_templates' => 'Active Templates',
'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Invoice number',
'form.invoice.person' => 'Person',
@@ -520,6 +477,7 @@
'form.tasks.inactive_tasks' => 'Inactive Tasks',
// Users form. See example at https://timetracker.anuko.com/users.php
+'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Role',
'form.users.manager' => 'Manager',
@@ -574,20 +532,26 @@
'form.group_edit.type_start_finish' => 'start and finish',
'form.group_edit.type_duration' => 'duration',
'form.group_edit.punch_mode' => 'Punch mode',
+'form.group_edit.one_uncompleted' => 'One uncompleted',
'form.group_edit.allow_overlap' => 'Allow overlap',
'form.group_edit.future_entries' => 'Future entries',
'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
'form.group_edit.confirm_save' => 'Confirm saving',
-'form.group_edit.allow_ip' => 'Allow IP',
+'form.group_edit.password_complexity' => 'Password complexity',
'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+'form.group_advanced_edit.allow_ip' => 'Allow IP',
+'form.group_advanced_edit.password_complexity' => 'Password complexity',
+'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'To',
'form.mail.report_subject' => 'Time Tracker Report',
-'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'Invoice sent.',
@@ -639,21 +603,8 @@
// Display Options form. See example at https://timetracker.anuko.com/display_options.php.
'form.display_options.note_on_separate_row' => 'Note on separate row',
'form.display_options.not_complete_days' => 'Not complete days',
+'form.display_options.inactive_projects' => 'Inactive projects',
+'form.display_options.cost_per_hour' => 'Cost per hour',
'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-'work.error.work_not_available' => 'Work item is not available.',
-'work.error.offer_not_available' => 'Offer is not available.',
-'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-'work.label.own_work' => 'Own work',
-'work.label.own_offers' => 'Own offers',
-'work.label.offers' => 'Offers',
-'work.label.message' => 'Message',
-'work.button.send_message' => 'Send message',
-'work.button.make_offer' => 'Make offer',
-'work.button.accept' => 'Accept',
-'work.button.decline' => 'Decline',
-'work.title.send_message' => 'Sending Message',
-'work.msg.message_sent' => 'Message sent.',
+'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/es.lang.php b/WEB-INF/resources/es.lang.php
index 0c1d2c6b9..b302de1c4 100644
--- a/WEB-INF/resources/es.lang.php
+++ b/WEB-INF/resources/es.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Tiempo',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Reportes',
@@ -62,7 +40,6 @@
'menu.users' => 'Personas',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
// 'menu.export' => 'Export',
'menu.clients' => 'Clientes',
'menu.options' => 'Opciones',
@@ -96,6 +73,8 @@
// 'error.record' => 'Select record.',
'error.auth' => 'Usuario o contraseña incorrecta.',
// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
// 'error.user_exists' => 'User with this login already exists.',
// 'error.object_exists' => 'Object with this name already exists.',
// 'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -119,7 +98,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -150,9 +128,11 @@
'button.import' => 'Importar grupo',
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -217,6 +197,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'Identificación',
// TODO: translate the following.
// 'label.language' => 'Language',
@@ -240,9 +221,6 @@
// 'label.ldap_hint' => 'Type your Windows login and password in the fields below.',
'label.required_fields' => '* - campos requeridos',
'label.on_behalf' => 'a nombre de',
-'label.role_manager' => '(manejador)',
-'label.role_comanager' => '(auxiliar del manejador)',
-'label.role_admin' => '(administrador)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -267,9 +245,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Solo totales',
@@ -286,20 +264,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -313,9 +279,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'Sesión iniciada',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Grupos',
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
// 'title.delete_group' => 'Deleting Group',
@@ -327,6 +294,7 @@
'title.delete_time_record' => 'Eliminando el historial de tiempo',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -412,22 +380,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -460,7 +412,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -476,7 +427,17 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => '¿Olvido su contraseña?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
// TODO: check / improve translation of form.reset_password.message.
@@ -485,10 +446,10 @@
'form.reset_password.message' => 'Se ha enviado la petición de reestablecer contraseña.',
'form.reset_password.email_subject' => 'Solicitud de reestablecimiento de la contraseña de Anuko Time Tracker',
// Note to translators: the ending of this string needs to be translated.
-// TODO: English string has changed. "from IP added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Querido usuario, Alguien, IP %s, solicitó reestablecer su contraseña de Anuko Time Tracker. Por favor visite este enlace si quiere reestablecer su contraseña.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+'form.reset_password.email_body' => "Querido usuario, Alguien, IP %s, solicitó reestablecer su contraseña de Anuko Time Tracker. Por favor visite este enlace si quiere reestablecer su contraseña.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: improve translation of form.change_password.tip.
@@ -527,10 +488,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Seleccionar perÃodo de tiempo',
'form.reports.set_period' => 'o establecer fechas',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Mostrar campos',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Agrupar por',
'form.reports.group_by_no' => '--- no agrupar ---',
'form.reports.group_by_date' => 'fecha',
@@ -545,6 +509,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exportar',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -558,8 +523,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Número de factura',
'form.invoice.person' => 'Persona',
@@ -585,6 +550,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Rol',
'form.users.manager' => 'Manejador',
@@ -648,13 +614,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -664,7 +636,7 @@
// TODO: translate form.mail.report_subject.
// 'form.mail.report_subject' => 'Time Tracker Report',
// Note to translators: the following strings need to be translated.
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'Factura enviada.',
@@ -722,21 +694,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/et.lang.php b/WEB-INF/resources/et.lang.php
index b6b442441..19a74b4cd 100644
--- a/WEB-INF/resources/et.lang.php
+++ b/WEB-INF/resources/et.lang.php
@@ -1,32 +1,9 @@
'Lisad',
'menu.time' => 'Ajaarvestus',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Kulud',
'menu.reports' => 'Raportid',
@@ -61,7 +39,6 @@
'menu.tasks' => 'Tööülesanded',
'menu.users' => 'Kasutajad',
'menu.groups' => 'Grupid',
-'menu.subgroups' => 'Alamgrupid',
'menu.export' => 'Eksport', // TODO: is this a correct term as an opposite of "Import"?
'menu.clients' => 'Kliendid',
'menu.options' => 'Suvandid',
@@ -89,6 +66,9 @@
'error.report' => 'Vali raport.',
'error.record' => 'Vali kirje.',
'error.auth' => 'Autentimine ebaõnnestus.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Selle nimega kasutaja on juba kasutusel.',
'error.object_exists' => 'Sellise nimega objekt on juba olemas.',
'error.invoice_exists' => 'Arve number on juba kasutusel.',
@@ -131,7 +111,6 @@
'error.expired' => 'Kehtivusaeg on lõppenud.',
// TODO: translate the following.
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
'warn.sure' => 'Oled kindel?',
@@ -157,10 +136,13 @@
'button.export' => 'Ekspordi grupp',
'button.import' => 'Impordi grupp',
'button.close' => 'Sulge',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'Stopp',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
@@ -217,6 +199,8 @@
'label.select_none' => 'Märgi kõik mittevalituks',
'label.day_view' => 'Päeva vaade',
'label.week_view' => 'Nädala vaade',
+// TODO: translate the following:
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Keel',
'label.decimal_mark' => 'Koma märk',
@@ -236,9 +220,6 @@
'label.required_fields' => '* nõutud väljad',
// TODO: Translate label.on_behalf, perhaps trying as "instead of".
// 'label.on_behalf' => 'on behalf of',
-'label.role_manager' => '(haldur)',
-'label.role_comanager' => '(kaashaldur)',
-'label.role_admin' => '(administraator)',
'label.page' => 'Lehekülg',
'label.condition' => 'Tingimus',
'label.yes' => 'jah',
@@ -262,10 +243,10 @@
'label.paid_status' => 'Makse olek',
'label.paid' => 'Makstud',
'label.mark_paid' => 'Märgi makstuks',
-// TODO: translate the following.
-// 'label.week_menu' => 'Week menu',
'label.week_note' => 'Nädala märge',
'label.week_list' => 'Nädala nimekiri',
+// TODO: translate the following:
+// 'label.weekends' => 'Weekends',
'label.work_units' => 'Töö ühikud',
'label.work_units_short' => 'Ühikud',
'label.totals_only' => 'Ainult summad',
@@ -282,21 +263,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'Aktiivsed kasutajad',
'label.inactive_users' => 'Mitteaktiivsed kasutajad',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -313,8 +281,9 @@
'title.error' => 'Viga',
'title.success' => 'Õnnestumine',
'title.login' => 'Sisene',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Grupid',
-'title.subgroups' => 'Alamgrupid',
'title.add_group' => 'Lisa grupp',
'title.edit_group' => 'Muuda gruppi',
'title.delete_group' => 'Kustuta grupp',
@@ -325,6 +294,7 @@
'title.delete_time_record' => 'Ajakande kustutamine',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Kulud',
'title.edit_expense' => 'Kulukirje muutmine',
'title.delete_expense' => 'Kulukirje kustutamine',
@@ -406,22 +376,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -452,7 +406,6 @@
'dropdown.delete' => 'kustuta',
'dropdown.do_not_delete' => 'ära kustuta',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
'dropdown.paid' => 'makstud',
@@ -463,12 +416,22 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Unustasid salasõna?',
-'form.login.about' => 'Anuko Time Tracker on lihtne, lihtsalt kasutatav ja avatud lähtekoodiga ajaarvestussüsteem.',
+'form.login.about' => 'Anuko Time Tracker on avatud lähtekoodiga ajaarvestussüsteem.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Salasõna tühistamise teade on saadetud e-postile.',
'form.reset_password.email_subject' => 'Anuko Time Tracker, parooli tühistamise nõue',
-'form.reset_password.email_body' => "Lugupeetud Kasutaja,\n\nIP-lt %s on nõutud Teie salasõna lähtestamist. Palun avage allolev link, kui soovite oma parooli lähtestada.\n\n%s\n\nAnuko Time Tracker on lihtne, lihtsalt kasutatav ja avatud lähtekoodiga ajaarvestussüsteem. Lisainfo saamiseks külastage https://www.anuko.com lehekülge.\n\n",
+'form.reset_password.email_body' => "Lugupeetud Kasutaja,\n\nIP-lt %s on nõutud Teie salasõna lähtestamist. Palun avage allolev link, kui soovite oma parooli lähtestada.\n\n%s\n\nAnuko Time Tracker on avatud lähtekoodiga ajaarvestussüsteem. Lisainfo saamiseks külastage https://www.anuko.com lehekülge.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Kirjuta siia oma uus parool ja salvesta.',
@@ -510,10 +473,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Vali ajaperiood',
'form.reports.set_period' => 'või märgi kuupäevad',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Näita välju',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Grupeeri',
'form.reports.group_by_no' => '--- grupeerimata ---',
'form.reports.group_by_date' => 'kuupäev',
@@ -525,6 +491,8 @@
// Report form. See example at https://timetracker.anuko.com/report.php
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Eksport',
+// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
'form.report.assign_to_invoice' => 'Lisa arvele',
// TODO: translate the following.
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -539,8 +507,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Arve number',
'form.invoice.person' => 'Isik',
@@ -562,6 +530,8 @@
'form.tasks.inactive_tasks' => 'Mitteaktiivsed tööülesanded',
// Users form. See example at https://timetracker.anuko.com/users.php
+// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
'form.users.uncompleted_entry' => 'Kasutajal on lõpetamata aja kanne',
'form.users.role' => 'Roll',
'form.users.manager' => 'Haldur',
@@ -620,21 +590,28 @@
'form.group_edit.type_start_finish' => 'algus ja lõpp',
'form.group_edit.type_duration' => 'vahemik',
'form.group_edit.punch_mode' => 'Kellast-kellani režiim',
+// TODO: translate the following.
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
'form.group_edit.allow_overlap' => 'Luba ajaline ülekate',
'form.group_edit.future_entries' => 'Tuleviku kirjed',
'form.group_edit.uncompleted_indicators' => 'Lõpetamata kirjete indikaator', // TODO: Fix this. Indicators (plural), not indicator.
'form.group_edit.confirm_save' => 'Kinnita salvestamine',
-'form.group_edit.allow_ip' => 'Luba IP',
// TODO: translate the following.
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+'form.group_advanced_edit.allow_ip' => 'Luba IP',
+// TODO: Translate the following.
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
'form.group_delete.hint' => 'Oled kindel, et soovid kogu gruppi kustutada?',
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Kellele',
'form.mail.report_subject' => 'Time Tracker raport',
-'form.mail.footer' => 'Anuko Time Tracker on lihtne, lihtsalt kasutatav ja avatud lähtekoodiga ajaarvestussüsteem. Lisainfo saamiseks külastage www.anuko.com lehekülge.',
+'form.mail.footer' => 'Anuko Time Tracker on avatud lähtekoodiga ajaarvestussüsteem. Lisainfo saamiseks külastage www.anuko.com lehekülge.',
'form.mail.report_sent' => 'Raport on saadetud.',
'form.mail.invoice_sent' => 'Arve on saadetud.',
@@ -691,21 +668,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/fa.lang.php b/WEB-INF/resources/fa.lang.php
index 35fb9feff..32dacdf00 100644
--- a/WEB-INF/resources/fa.lang.php
+++ b/WEB-INF/resources/fa.lang.php
@@ -1,33 +1,11 @@
'پلاگین ها',
'menu.time' => 'زمان',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'هزينه ها',
'menu.reports' => 'گزارشات',
@@ -62,7 +41,6 @@
'menu.users' => 'کاربران',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'پشتیبانی',
'menu.clients' => 'مشتری ها',
'menu.options' => 'تنظیمات',
@@ -95,6 +73,9 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
'error.auth' => 'نام کاربری یا رمز عبور اشتباه است.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'کاربری با این نام کاربری موجود است.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -126,7 +107,6 @@
// 'error.expired' => 'Expiration date reached.',
// TODO: translate the following.
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -154,10 +134,13 @@
'button.export' => 'ایجاد پشتیبان از تیم', // TODO: replace "team" with "group".
'button.import' => 'وارد کردن تیم', // TODO: replace "team" with "group".
'button.close' => 'بستن',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'توقÙ',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -220,6 +203,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'شناسه',
'label.language' => 'زبان',
// TODO: translate the following.
@@ -239,9 +223,6 @@
'label.ldap_hint' => 'نام کاربری ویندوزو رمزعبورخود را در Ùیلدهای زیر وارد کنید',
'label.required_fields' => '* - Ùیلد های اجباری',
'label.on_behalf' => 'از دیدگاه',
-'label.role_manager' => '(مدیر)',
-'label.role_comanager' => '(دستیار مدیر)',
-'label.role_admin' => '(مدیر ارشد)',
// Translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -267,9 +248,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
// 'label.totals_only' => 'Totals only',
@@ -285,21 +266,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'کاربران ÙØ¹Ø§Ù„',
'label.inactive_users' => 'کاربران ØºÛŒØ±ÙØ¹Ø§Ù„',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -313,9 +281,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'ورود',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'تیم ها', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'ØØ°Ù تیم', // TODO: change "team" to "group".
@@ -326,6 +295,7 @@
'title.delete_time_record' => 'ØØ°Ù رکورد زمان',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'هزینه ها',
'title.edit_expense' => 'ویرایش آیتم هزینه ها',
'title.delete_expense' => 'ØØ°Ù آیتم هزینه ها',
@@ -406,22 +376,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -457,7 +411,6 @@
// TODO: translate the following.
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -472,16 +425,26 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'بازیابی رمز عبور؟',
-// TODO: translate form.login.about.
-'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// TODO: translate the following.
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'درخواست بازیابی رمزعبور به ایمیل ÙØ±Ø³ØªØ§Ø¯Ù‡ شد.',
// TODO: check translation of form.reset_password.email_subject. This is the subject for email message for password reset. Below is the English original.
// 'form.reset_password.email_subject' => 'Anuko Time Tracker password reset request',
'form.reset_password.email_subject' => 'درخواست بازیابی رمزعبور ÙØ±Ø³ØªØ§Ø¯Ù‡ شد',
-// TODO: English string has changed. "from IP added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Older translation is below.
// 'form.reset_password.email_body' => "کاربران گرامی\n\n یک Ù†ÙØ±ØŒ شاید خودتان، درخواست بازیابی رمزعبور نرم Ø§ÙØ²Ø§Ø± رهگیری زمان شما را داشته است.Ù„Ø·ÙØ§ برای تغییر رمزعبور روی لینک زیر کلیک کنید: \n\n%s\n\n",
@@ -519,10 +482,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'انتخاب بازه زمانی',
'form.reports.set_period' => 'یا تعیین تاریخ',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'نمایش Ùیلدها',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'گروه بندی شده با',
'form.reports.group_by_no' => '--- بدون گروه ---',
'form.reports.group_by_date' => 'تاریخ',
@@ -535,6 +501,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'پشتیبانی',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -548,8 +515,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'شماره ÙØ§Ú©ØªÙˆØ±',
'form.invoice.person' => 'شخص',
@@ -573,6 +540,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+ // 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'سمت',
'form.users.manager' => 'مدیر',
@@ -634,13 +602,19 @@
'form.group_edit.type_duration' => 'مدت زمان',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -649,7 +623,7 @@
'form.mail.to' => 'به',
'form.mail.report_subject' => 'گزارش تایم شیت',
// TODO: translate form.mail.footer.
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
'form.mail.report_sent' => 'گزارش ارسال شد.',
'form.mail.invoice_sent' => 'ÙØ§Ú©ØªÙˆØ± ارسال شد.',
@@ -707,21 +681,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/fi.lang.php b/WEB-INF/resources/fi.lang.php
index 753dcf8ce..cdfc4c5fe 100644
--- a/WEB-INF/resources/fi.lang.php
+++ b/WEB-INF/resources/fi.lang.php
@@ -1,32 +1,9 @@
'Lisäosat',
'menu.time' => 'Tunnit',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Kulut',
'menu.reports' => 'Raportit',
@@ -61,7 +39,6 @@
'menu.users' => 'Käyttäjät',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Vie',
'menu.clients' => 'Asiakkaat',
'menu.options' => 'Optiot',
@@ -92,6 +69,9 @@
// TODO: translate the following.
// 'error.record' => 'Select record.',
'error.auth' => 'Virheellinen käyttäjänimi tai salasana.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Tämä käyttäjänimi on jo olemassa.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -120,7 +100,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -148,10 +127,13 @@
'button.export' => 'Vie tiimi', // TODO: replace "team" with "group".
'button.import' => 'Tuo tiimi', // TODO: replace "team" with "group".
'button.close' => 'Sulje',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'Lopeta',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -213,6 +195,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Kieli',
'label.decimal_mark' => 'Desimaalierotin',
@@ -231,9 +214,6 @@
'label.ldap_hint' => 'Syötä Windows-käyttäjätunnuksesi ja salasanasi ao. kenttiin.',
'label.required_fields' => '* - pakolliset kentät',
'label.on_behalf' => 'puolesta',
-'label.role_manager' => '(esimies)',
-'label.role_comanager' => '(apu-esimies)',
-'label.role_admin' => '(ylläpitäjä)',
'label.page' => 'Sivu',
// TODO: translate the following.
// 'label.condition' => 'Condition',
@@ -259,9 +239,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Vain yhteissummat',
@@ -278,21 +258,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'Aktiiviset käyttäjät',
'label.inactive_users' => 'Ei-aktiiviset käyttäjät',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -306,9 +273,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'Kirjautuminen',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Tiimit', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
'title.edit_group' => 'Tiimin muokkaus', // TODO: change "team" to "group".
'title.delete_group' => 'Tiimin poisto', // TODO: change "team" to "group".
@@ -319,6 +287,7 @@
'title.delete_time_record' => 'Tuntikirjausten poisto',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Kulut',
'title.edit_expense' => 'Kulutietojen muokkaus',
'title.delete_expense' => 'Kulutiedon poisto',
@@ -397,22 +366,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -445,7 +398,6 @@
'dropdown.delete' => 'poista',
'dropdown.do_not_delete' => 'älä poista',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -460,15 +412,26 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Salasana unohtunut?',
-'form.login.about' => 'Anuko Time Tracker on yksinkertainen ja helppokäyttöinen vapaan koodin tuntiseurantaohjelmisto.',
+// TODO: check translation of form.login.about - is open source "vapaan koodin"?
+'form.login.about' => 'Anuko Time Tracker on vapaan koodin tuntiseurantaohjelmisto.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Salasanan nollauspyyntöviesti lähetetty.',
'form.reset_password.email_subject' => 'Anuko Time Tracker -salasanan nollauspyyntö',
-// TODO: English string has changed. "from IP added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Hyvä käyttäjä,\n\nJoku, IP %s, on pyytänyt nollaamaan Anuko Time Tracker -ohjelman salasanasi. Jos haluat nollata salasanasi, käy sivulla \n\n%s\n\nAnuko Time Tracker on yksinkertainen ja helppokäyttöinen vapaan koodin tuntiseurantaohjelmisto. Lisätietoja sivulla https://www.anuko.com.\n\n",
+'form.reset_password.email_body' => "Hyvä käyttäjä,\n\nJoku, IP %s, on pyytänyt nollaamaan Anuko Time Tracker -ohjelman salasanasi. Jos haluat nollata salasanasi, käy sivulla \n\n%s\n\nAnuko Time Tracker on vapaan koodin tuntiseurantaohjelmisto. Lisätietoja sivulla https://www.anuko.com.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Syötä uusi salasana ja osoita Tallenna.',
@@ -503,10 +466,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Valitse ajanjakso',
'form.reports.set_period' => 'tai aseta päivät',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Näytä kentät',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Ryhmittelyperuste',
'form.reports.group_by_no' => '--- ei ryhmitystä ---',
'form.reports.group_by_date' => 'päivä',
@@ -519,6 +485,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Vie',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -532,8 +499,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Laskun numero',
'form.invoice.person' => 'Henkilö',
@@ -557,6 +524,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Rooli',
'form.users.manager' => 'Esimies',
@@ -617,13 +585,19 @@
'form.group_edit.type_duration' => 'kesto',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -631,6 +605,7 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Vastaanottaja',
'form.mail.report_subject' => 'Time Tracker -raportti',
+// TODO: English string for form.mail.footer changed. Re-translate.
'form.mail.footer' => 'Anuko Time Tracker on yksinkertainen ja helppokäyttöinen vapaan koodin tuntiseurantaohjelmisto. Lisätietoja sivulla www.anuko.com.',
'form.mail.report_sent' => 'Raportti lähetetty.',
'form.mail.invoice_sent' => 'Lasku lähetetty.',
@@ -689,21 +664,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/fr.lang.php b/WEB-INF/resources/fr.lang.php
index ca00e9471..b488be0bc 100644
--- a/WEB-INF/resources/fr.lang.php
+++ b/WEB-INF/resources/fr.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Temps',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Dépenses',
'menu.reports' => 'Rapports',
@@ -61,7 +39,6 @@
'menu.users' => 'Utilisateurs',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Exporter',
'menu.clients' => 'Clients',
'menu.options' => 'Options',
@@ -90,6 +67,9 @@
// TODO: translate the following.
// 'error.record' => 'Select record.',
'error.auth' => 'Nom d\\\'utilisateur ou mot de passe incorrect.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Un utilisateur avec cet identifiant existe déjà .',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -118,7 +98,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -146,10 +125,13 @@
'button.export' => 'Exporter l\\\'équipe', // TODO: replace "team" with "group".
'button.import' => 'Importer une équipe', // TODO: replace "team" with "group".
'button.close' => 'Fermer',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'Arrêter',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -209,6 +191,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Langage',
'label.decimal_mark' => 'Séparateur de décimal',
@@ -227,9 +210,6 @@
'label.ldap_hint' => 'Entrer votre Identifiant Windows et votre mot de passe dans les champs suivants.',
'label.required_fields' => '* - champs obligatoires',
'label.on_behalf' => 'de la part de',
-'label.role_manager' => '(responsable)',
-'label.role_comanager' => '(coresponsable)',
-'label.role_admin' => '(administrateur)',
'label.page' => 'Page',
'label.condition' => 'Condition',
// TODO: translate the following.
@@ -253,9 +233,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Totaux uniquement',
@@ -272,21 +252,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'Utilisateurs actifs',
'label.inactive_users' => 'Utilisateurs inactifs',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -300,9 +267,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'Connexion',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Équipes', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
'title.edit_group' => 'Modification d\\\'une équipe', // TODO: change "team" to "group".
'title.delete_group' => 'Suppression d\\\'une équipe', // TODO: change "team" to "group".
@@ -313,6 +281,7 @@
'title.delete_time_record' => 'Suppression de l\\\'entrée de temps',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Dépenses',
'title.edit_expense' => 'Modification d\\\'une dépense',
'title.delete_expense' => 'Suppression d\\\'une dépense',
@@ -391,22 +360,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -437,7 +390,6 @@
'dropdown.delete' => 'supprimer',
'dropdown.do_not_delete' => 'ne pas supprimer',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -452,15 +404,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Mot de passe oublié?',
-'form.login.about' => 'Anuko Time Tracker est un système de gestion du temps, open source, simple et facile à utiliser.',
+'form.login.about' => 'Anuko Time Tracker est un système de gestion du temps, open source.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Une demande de réinitialisation du mot de passe a été envoyé par courriel.',
'form.reset_password.email_subject' => 'Demande de réinitialisation de mot de passe Anuko Time Tracker',
-// TODO: English string has changed. "from IP added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Cher utilisateur,\n\nQuelqu\'un, IP %s, avez demandé une réinitialisation de votre mot de passe. Veuillez de suivre ce lien pour le réinitialiser\n\n%s\n\nAnuko Time Tracker est un système de gestion du temps, open source, simple et facile à utiliser. Visitez https://www.anuko.com pour plus d\'informations.\n\n",
+'form.reset_password.email_body' => "Cher utilisateur,\n\nQuelqu\'un, IP %s, avez demandé une réinitialisation de votre mot de passe. Veuillez de suivre ce lien pour le réinitialiser\n\n%s\n\nAnuko Time Tracker est un système de gestion du temps, open source. Visitez https://www.anuko.com pour plus d\'informations.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Saisissez votre nouveau mot de passe et cliquez sur Sauvegarder.',
@@ -495,10 +457,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Sélectionner la période de temps',
'form.reports.set_period' => 'ou dates indiquées',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Afficher les champs',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Regroupés par',
'form.reports.group_by_no' => '--- Aucun regroupement ---',
'form.reports.group_by_date' => 'Date',
@@ -511,6 +476,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exporter',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -524,8 +490,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Numéro de facture',
'form.invoice.person' => 'Personne',
@@ -548,6 +514,8 @@
'form.tasks.inactive_tasks' => 'Tâches inactives',
// Users form. See example at https://timetracker.anuko.com/users.php
+// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
'form.users.uncompleted_entry' => 'L\\\'utilisateur a une entrée incomplète',
'form.users.role' => 'Rôle',
'form.users.manager' => 'Responsable',
@@ -608,13 +576,19 @@
'form.group_edit.type_duration' => 'Durée',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -622,7 +596,7 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'À',
'form.mail.report_subject' => 'Rapport Time Tracker',
-'form.mail.footer' => 'Anuko Time Tracker est un système de gestion du temps, open source, simple et facile à utiliser. Visitez www.anuko.com pour plus d\\\'informations.',
+'form.mail.footer' => 'Anuko Time Tracker est un système de gestion du temps, open source. Visitez www.anuko.com pour plus d\\\'informations.',
'form.mail.report_sent' => 'Le rapport a été envoyé.',
'form.mail.invoice_sent' => 'La facture a été envoyée.',
@@ -679,21 +653,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/gr.lang.php b/WEB-INF/resources/gr.lang.php
index ba630f269..34f1890eb 100644
--- a/WEB-INF/resources/gr.lang.php
+++ b/WEB-INF/resources/gr.lang.php
@@ -1,32 +1,9 @@
'Î Ïόσθετα',
'menu.time' => 'ΧÏόνος',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Έξοδα',
'menu.reports' => 'ΑναφοÏÎÏ‚',
@@ -59,8 +37,6 @@
'menu.tasks' => 'ΕÏγασίες',
'menu.users' => 'ΧÏήστες',
'menu.groups' => 'Ομάδες',
-// TODO: translate the following.
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Εξαγωγή',
'menu.clients' => 'Πελάτες',
'menu.options' => 'ΕπιλογÎÏ‚',
@@ -88,6 +64,9 @@
'error.report' => 'Επιλογή αναφοÏάς.',
'error.record' => 'Επιλογή εγγÏαφής.',
'error.auth' => 'ΛανθασμÎνο όνομα εισόδου ή κωδικός.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Ο χÏήστης με αυτήν τη σÏνδεση υπάÏχει ήδη.',
'error.object_exists' => 'Το αντικείμενο με αυτό το όνομα υπάÏχει ήδη.',
'error.invoice_exists' => 'Το τιμολόγιο με αυτόν τον αÏιθμό υπάÏχει ήδη.',
@@ -114,7 +93,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -142,10 +120,13 @@
'button.export' => 'Εξαγωγη ομάδας',
'button.import' => 'Εισαγωγή ομάδας',
'button.close' => 'Κλείσιμο',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'ΤÎλος',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -203,6 +184,8 @@
'label.select_none' => 'Μη επιλογή',
'label.day_view' => 'Î Ïοβολή ημÎÏας',
'label.week_view' => 'Î Ïοβολή εβδομάδας',
+// TODO: translate the following:
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Γλώσσα',
'label.decimal_mark' => 'Δεκαδική Îνδειξη',
@@ -221,9 +204,6 @@
'label.ldap_hint' => 'Εισάγετε το όνομα σÏνδεσης των Windows και κωδικό Ï€Ïόσβασης στα παÏακάτω πεδία.',
'label.required_fields' => '* - υποχÏεωτικά πεδία',
'label.on_behalf' => 'εκ μÎÏους του',
-'label.role_manager' => '(Διευθυντής)',
-'label.role_comanager' => '(Υποδιευθυντής)',
-'label.role_admin' => '(ΔιαχειÏιστής)',
'label.page' => 'Σελίδα',
'label.condition' => 'Κατάσταση',
'label.yes' => 'ναι',
@@ -247,11 +227,10 @@
'label.paid_status' => 'Κατάσταση πληÏωμής',
'label.paid' => 'ΠληÏωμÎνο',
'label.mark_paid' => 'Σήμανση πληÏωμÎνα',
-// TODO: translate the following.
-// 'label.week_menu' => 'Week menu',
'label.week_note' => 'Σημείωση εβδομάδας',
'label.week_list' => 'Λίστα εβδομάδων',
// TODO: translate the following.
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'ΣÏνολα μόνο',
@@ -268,21 +247,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'ΕνεÏγοί χÏήστες',
'label.inactive_users' => 'ΑνενεÏγοί χÏήστες',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -296,9 +262,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'ΣÏνδεση',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Ομάδες',
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
'title.edit_group' => 'ΕπεξεÏγασία ομάδας',
'title.delete_group' => 'ΔιαγÏαφή ομάδας',
@@ -309,6 +276,7 @@
'title.delete_time_record' => 'ΔιαγÏαφή χÏόνου',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Δαπάνες',
'title.edit_expense' => 'ΕπεξεÏγασία δαπάνης',
'title.delete_expense' => 'ΔιαγÏαφή δαπάνης',
@@ -390,22 +358,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -436,7 +388,6 @@
'dropdown.delete' => 'διαγÏαφή',
'dropdown.do_not_delete' => 'μη το διαγÏάψετε',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
'dropdown.paid' => 'εξοφλημÎνο',
@@ -452,12 +403,22 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Ξεχάσατε τον κωδικό Ï€Ïόσβασης;',
-'form.login.about' => 'Anuko Time Tracker είναι Îνα απλό, εÏχÏηστο, Î±Î½Î¿Î¹ÎºÏ„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± σÏστημα παÏακολοÏθησης χÏόνου.',
+'form.login.about' => 'Anuko Time Tracker είναι Îνα Î±Î½Î¿Î¹ÎºÏ„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± σÏστημα παÏακολοÏθησης χÏόνου.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Το αίτημα επαναφοÏάς ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης αποστÎλλεται μÎσω ηλεκτÏÎ¿Î½Î¹ÎºÎ¿Ï Ï„Î±Ï‡Ï…Î´Ïομείου.',
'form.reset_password.email_subject' => 'Αίτημα επαναφοÏάς ÎºÏ‰Î´Î¹ÎºÎ¿Ï Anuko Time Tracker',
-'form.reset_password.email_body' => "ΑγαπητΠχÏήστη,\n\nΚάποιος από την IP %s ζήτησε επαναφοÏά του ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης στο Anuko Time Tracker. Πατήστε στον ακόλουθο σÏνδεσμο για επαναφοÏά του ÎºÏ‰Î´Î¹ÎºÎ¿Ï ÏƒÎ±Ï‚.\n\n%s\n\nΤο Anuko Time Tracker είναι Îνα απλό, εÏχÏηστο, Î±Î½Î¿Î¹ÎºÏ„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± σÏστημα παÏακολοÏθησης χÏόνου. Επισκεφθείτε τη διεÏθυνση https://www.anuko.com για πεÏισσότεÏες πληÏοφοÏίες.\n\n",
+'form.reset_password.email_body' => "ΑγαπητΠχÏήστη,\n\nΚάποιος από την IP %s ζήτησε επαναφοÏά του ÎºÏ‰Î´Î¹ÎºÎ¿Ï Ï€Ïόσβασης στο Anuko Time Tracker. Πατήστε στον ακόλουθο σÏνδεσμο για επαναφοÏά του ÎºÏ‰Î´Î¹ÎºÎ¿Ï ÏƒÎ±Ï‚.\n\n%s\n\nΤο Anuko Time Tracker είναι Îνα Î±Î½Î¿Î¹ÎºÏ„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± σÏστημα παÏακολοÏθησης χÏόνου. Επισκεφθείτε τη διεÏθυνση https://www.anuko.com για πεÏισσότεÏες πληÏοφοÏίες.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'ΠληκτÏολογήστε νÎο κωδικό Ï€Ïόσβασης και κάντε κλικ στην επιλογή Αποθήκευση.',
@@ -491,10 +452,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Επιλογή χÏονικής πεÏιόδου',
'form.reports.set_period' => 'ή εÏÏος ημεÏομηνιών',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Εμφάνιση πεδίων',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Ομαδοποίηση με βάση',
'form.reports.group_by_no' => '--- χωÏίς ομαδοποίηση ---',
'form.reports.group_by_date' => 'ημεÏομηνία',
@@ -506,6 +470,8 @@
// Report form. See example at https://timetracker.anuko.com/report.php
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Εξαγωγή',
+// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
'form.report.assign_to_invoice' => 'Ανάθεση στο τιμολόγιο',
// TODO: translate the following.
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -520,8 +486,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'ΑÏιθμός τιμολογίου',
'form.invoice.person' => 'Άτομο',
@@ -543,6 +509,8 @@
'form.tasks.inactive_tasks' => 'ΑνενεÏγÎÏ‚ εÏγασίες',
// Users form. See example at https://timetracker.anuko.com/users.php
+// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
'form.users.uncompleted_entry' => 'Ο χÏήστης Îχει μια μη ολοκληÏωμÎνη εισαγωγή χÏόνου',
'form.users.role' => 'Ρόλος',
'form.users.manager' => 'Διευθυντής',
@@ -599,14 +567,21 @@
'form.group_edit.type_start_finish' => 'αÏχή και Ï„Îλος',
'form.group_edit.type_duration' => 'διάÏκεια',
'form.group_edit.punch_mode' => 'ΛειτουÏγία διάτÏησης',
+// TODO: translate the following.
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
'form.group_edit.allow_overlap' => 'Επικάλυψη επιτÏεπτή',
'form.group_edit.future_entries' => 'ΜελλοντικÎÏ‚ καταχωÏήσεις',
'form.group_edit.uncompleted_indicators' => 'Μη ολοκληÏωμÎνες ενδείξεις',
// TODO: translate the following.
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -614,7 +589,7 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Î Ïος',
'form.mail.report_subject' => 'Time Tracker αναφοÏά',
-'form.mail.footer' => 'Το Anuko Time Tracker είναι Îνα απλό, εÏχÏηστο, Î±Î½Î¿Î¹ÎºÏ„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± σÏστημα παÏακολοÏθησης χÏόνου. Επισκεφθείτε τη διεÏθυνση www.anuko.com για πεÏισσότεÏες πληÏοφοÏίες.',
+'form.mail.footer' => 'Το Anuko Time Tracker είναι Îνα Î±Î½Î¿Î¹ÎºÏ„Î¿Ï ÎºÏŽÎ´Î¹ÎºÎ± σÏστημα παÏακολοÏθησης χÏόνου. Επισκεφθείτε τη διεÏθυνση www.anuko.com για πεÏισσότεÏες πληÏοφοÏίες.',
'form.mail.report_sent' => 'Η αναφοÏά στάλθηκε.',
'form.mail.invoice_sent' => 'Το τιμολόγιο στάλθηκε.',
@@ -672,21 +647,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/he.lang.php b/WEB-INF/resources/he.lang.php
index 296e82b1b..585a7ec2f 100644
--- a/WEB-INF/resources/he.lang.php
+++ b/WEB-INF/resources/he.lang.php
@@ -1,32 +1,9 @@
'תוספי×',
'menu.time' => 'זמן',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'דוחות',
@@ -62,7 +40,6 @@
'menu.users' => 'משתמשי×',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'ייצו×',
'menu.clients' => 'לקוחות',
'menu.options' => '×פשרויות',
@@ -105,6 +82,9 @@
// 'error.report' => 'Select report.'
// 'error.record' => 'Select record.',
'error.auth' => '×©× ×ž×©×ª×ž×© ×ו סיסמה שגויי×',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => '×©× ×ž×©×ª×ž×© כבר ×§×™×™×',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -134,7 +114,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -162,10 +141,13 @@
'button.export' => '×™×™×¦× ×¦×•×•×ª', // TODO: replace "team" with "group".
'button.import' => '×™×™×‘× ×¦×•×•×ª', // TODO: replace "team" with "group".
'button.close' => 'סגור',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'עצור',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -228,6 +210,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'מזהה',
'label.language' => 'שפה',
// TODO: translate the following.
@@ -247,9 +230,6 @@
'label.ldap_hint' => '×”×›× ×¡ ×ת ×©× ×”×ž×©×ª×ž×© ו×ת הסיסמה של ×•×•×™× ×“×•×– בשדות.',
'label.required_fields' => '* - שדות חובה',
'label.on_behalf' => 'מטע×',
-'label.role_manager' => '(×ž× ×”×œ)',
-'label.role_comanager' => '(×ž× ×”×œ ×ž×©× ×”)',
-'label.role_admin' => '(×ž× ×”×œ המערכת)',
// Translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -274,9 +254,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'labl.totals_only' => '×¡×™×›×•×ž×™× ×‘×œ×‘×“',
@@ -293,21 +273,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => '×ž×©×ª×ž×©×™× ×¤×¢×™×œ×™×',
'label.inactive_users' => '×ž×©×ª×ž×©×™× ×œ× ×¤×¢×™×œ×™×',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -321,9 +288,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => '×›× ×™×¡×”',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'צוותי×', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'מחיקת צוות', // TODO: change "team" to "group".
@@ -334,6 +302,7 @@
'title.delete_time_record' => 'מחיקת רשומה',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -413,22 +382,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -462,7 +415,6 @@
// TODO: translate the following.
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -477,13 +429,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'שכחת סיסמה?',
+ // TODO: re-translate form.login.about as it has changed.
+ // 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
'form.login.about' => 'Anuko Time Tracker ×”×™× ×” מערכת פשוטה, קלה לשימוש ×•×—×™× ×ž×™×ª ×œ× ×™×”×•×œ זמן.',
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
+
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'הבקשה ל×יפוס בסיסמה × ×©×œ×—×” בדו×ר ××œ×§×˜×¨×•× ×™.',
'form.reset_password.email_subject' => 'בקשה ל×יפוס סיסמה למערכת Anuko Time Tracker',
-// TODO: English string has changed. "from IP added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Older translation is below.
// 'form.reset_password.email_body' => "משתמש יקר,\n\n התקבלה בקשה ל×יפוס סיסמתך. × × ×œ×œ×—×•×¥ על קישור ×–×” ×× ×‘×¨×¦×•× ×š ל×פס ×ת הסיסמה.\n\n%s\n\n. Anuko Time Tracker ×”×™× ×” מערכת ×œ× ×™×”×•×œ זמן פשוטה ×•×—×™× ×ž×™×ª. בקר ב××ª×¨× ×• בכתובת https://www.anuko.com ×œ×¤×¨×˜×™× × ×•×¡×¤×™×.\n\n",
@@ -520,10 +484,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'בחר תקופת זמן',
'form.reports.set_period' => '×ו הגדר ת×ריכי×',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'הר××” שדות',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'סדר לפי',
'form.reports.group_by_no' => '--- ×œ×œ× ×¡×“×¨ ---',
'form.reports.group_by_date' => 'ת×ריך',
@@ -537,6 +504,7 @@
// TODO: form.report.export is just "Export" now in the English file. Shorten this translation.
'form.report.export' => '×™×™×¦× × ×ª×•× ×™× ×‘×ª×‘× ×™×ª',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -550,8 +518,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'מספר ×—×©×‘×•× ×™×ª',
'form.invoice.person' => 'משתמש',
@@ -575,6 +543,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'תפקיד',
'form.users.manager' => '×ž× ×”×œ',
@@ -636,13 +605,19 @@
'form.group_edit.type_duration' => 'משך זמן',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -650,6 +625,8 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => '×ל',
'form.mail.report_subject' => 'דוח Time Tracker',
+// TODO: retranslate form.mail.footer as the English string has changed.
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
'form.mail.footer' => 'Anuko Time Tracker ×”×™× ×” מערכת פשוטה, קלה לשימוש ×•×—×™× ×ž×™×ª ×œ× ×™×”×•×œ זמן. בקר ב×תר www.anuko.com ×œ×¤×¨×˜×™× × ×•×¡×¤×™×.',
'form.mail.report_sent' => 'הדוח × ×©×œ×—.',
'form.mail.invoice_sent' => '×”×—×©×‘×•× ×™×ª × ×©×œ×—×”.',
@@ -708,21 +685,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/hu.lang.php b/WEB-INF/resources/hu.lang.php
index 6328f330f..e2d7500d3 100644
--- a/WEB-INF/resources/hu.lang.php
+++ b/WEB-INF/resources/hu.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Munkaidő',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Riportok',
@@ -64,8 +42,6 @@
// 'menu.users' => 'Users',
'menu.groups' => 'Csoportok',
// TODO: translate the following.
-// 'menu.subgroups' => 'Subgroups',
-// TODO: translate the following.
// 'menu.export' => 'Export',
'menu.clients' => 'Ügyfelek',
'menu.options' => 'Opciók',
@@ -99,6 +75,8 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
// 'error.auth' => 'Incorrect login or password.',
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
// 'error.user_exists' => 'User with this login already exists.',
// 'error.object_exists' => 'Object with this name already exists.',
// 'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -123,7 +101,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -154,9 +131,11 @@
'button.import' => 'Csoport importálása',
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -223,6 +202,7 @@
'label.select_none' => 'Senkit nem jelöl ki',
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'AzonosÃtó',
// TODO: translate the following.
// 'label.language' => 'Language',
@@ -244,9 +224,6 @@
// 'label.ldap_hint' => 'Type your Windows login and password in the fields below.',
'label.required_fields' => '* kötelezően kitöltendő mezők',
'label.on_behalf' => 'helyett',
-'label.role_manager' => '(vezető)',
-'label.role_comanager' => '(helyettes)',
-'label.role_admin' => '(adminisztrátor)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -271,9 +248,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
// 'label.totals_only' => 'Totals only',
@@ -289,20 +266,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -316,9 +281,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'Bejelentkezés',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Csoportok',
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'Csoport törlése',
@@ -329,6 +295,7 @@
// 'title.edit_time_record' => 'Editing Time Record',
// 'title.delete_time_record' => 'Deleting Time Record',
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -413,22 +380,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -463,7 +414,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -474,13 +424,23 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Elfelejtetted a jelszót?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
// TODO: translate the following.
// 'form.reset_password.message' => 'Password reset request sent by email.',
// 'form.reset_password.email_subject' => 'Anuko Time Tracker password reset request',
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -519,9 +479,11 @@
'form.reports.select_period' => 'Jelölj meg egy időszakot',
'form.reports.set_period' => 'vagy állÃts be konkrét dátumot',
// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
// 'form.reports.show_fields' => 'Show fields',
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'CsoportosÃtva',
'form.reports.group_by_no' => '--- csoportosÃtás nélkül ---',
'form.reports.group_by_date' => 'dátum',
@@ -536,6 +498,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exportálása', // TODO: is this correct?
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -549,8 +512,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Számla azonosÃtó száma',
'form.invoice.person' => 'Személy',
@@ -576,6 +539,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Szerepkör',
'form.users.manager' => 'Vezető',
@@ -639,13 +603,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -654,7 +624,7 @@
'form.mail.to' => 'CÃmzett',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'A számla elküldve.',
@@ -712,21 +682,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/it.lang.php b/WEB-INF/resources/it.lang.php
index e3bc6a31d..73ca8a022 100644
--- a/WEB-INF/resources/it.lang.php
+++ b/WEB-INF/resources/it.lang.php
@@ -1,32 +1,9 @@
'Plugin',
'menu.time' => 'Tempo',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Spese',
'menu.reports' => 'Rapporti',
@@ -61,8 +39,6 @@
'menu.tasks' => 'Compiti',
'menu.users' => 'Utenti',
'menu.groups' => 'Gruppi',
-// TODO: translate the following.
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Esportazione',
'menu.clients' => 'Clienti',
'menu.options' => 'Opzioni',
@@ -90,6 +66,9 @@
'error.report' => 'Seleziona rapporto.',
'error.record' => 'Seleziona record.',
'error.auth' => 'Login o password errati.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Esiste già un utente con questo username.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -118,7 +97,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -146,10 +124,13 @@
'button.export' => 'Esporta gruppo',
'button.import' => 'Importa gruppo',
'button.close' => 'Chiudi',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'Stop',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -207,6 +188,8 @@
'label.select_none' => 'Deseleziona tutti',
'label.day_view' => 'Vista giornaliera',
'label.week_view' => 'Vista settimanale',
+// TODO: translate the following:
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Lingua',
'label.decimal_mark' => 'Separatore decimale',
@@ -225,9 +208,6 @@
'label.ldap_hint' => 'Digita il tuo Login Windows e la tua password nei campi qui sotto.',
'label.required_fields' => '* campi obbligatori',
'label.on_behalf' => 'a favore di',
-'label.role_manager' => '(manager)',
-'label.role_comanager' => '(co-manager)',
-'label.role_admin' => '(amministratore)',
'label.page' => 'Pagina',
'label.condition' => 'Condizione',
'label.yes' => 'si',
@@ -251,11 +231,10 @@
'label.paid_status' => 'Stato pagamento',
'label.paid' => 'Pagato',
'label.mark_paid' => 'Segna come pagato',
-// TODO: translate the following.
-// 'label.week_menu' => 'Week menu',
'label.week_note' => 'Nota settimanale',
'label.week_list' => 'Lista settimanale',
// TODO: translate the following.
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Solo i totali',
@@ -272,21 +251,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'Utenti attivi',
'label.inactive_users' => 'Utenti inattivi',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -304,9 +270,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'Login',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Gruppi',
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
'title.edit_group' => 'Modifica gruppo',
'title.delete_group' => 'Elimina gruppo',
@@ -317,6 +284,7 @@
'title.delete_time_record' => 'Eliminazione record temporale',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Spese',
'title.edit_expense' => 'Modifica voce di spesa',
'title.delete_expense' => 'Eliminezione voce di spesa',
@@ -400,22 +368,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -446,7 +398,6 @@
'dropdown.delete' => 'elimina',
'dropdown.do_not_delete' => 'non eliminare',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
'dropdown.paid' => 'pagato',
@@ -462,15 +413,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Password dimenticata?',
-'form.login.about' => 'Anuko Time Tracker è un sistema semplice e open source per registrare i tempi di lavoro.',
+'form.login.about' => 'Anuko Time Tracker è un sistema open source per registrare i tempi di lavoro.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Richiesta di reset password inviata via mail.',
'form.reset_password.email_subject' => 'Richiesta reset password per Anuko Time Tracker',
-// TODO: English string has changed. "from IP added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate the beginning.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Caro utente,\n\n qualcuno, IP %s, ha richiesto di reimpostare la tua password per Anuko Time Tracker. Per favore visita questo link per reimpostare la tua password.\n\n%s\n\nAnuko Time Tracker è un sistema semplice e open source per registrare i tempi di lavoro. Visita https://www.anuko.com per maggiori informazioni.\n\n",
+'form.reset_password.email_body' => "Caro utente,\n\n qualcuno, IP %s, ha richiesto di reimpostare la tua password per Anuko Time Tracker. Per favore visita questo link per reimpostare la tua password.\n\n%s\n\nAnuko Time Tracker è un sistema open source per registrare i tempi di lavoro. Visita https://www.anuko.com per maggiori informazioni.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Digita una nuova password e clicca su Salva.',
@@ -504,10 +465,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Seleziona il periodo di tempo',
'form.reports.set_period' => 'oppure setta le date',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Mostra i campi',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Raggruppa per',
'form.reports.group_by_no' => '--- non raggruppare ---',
'form.reports.group_by_date' => 'data',
@@ -519,6 +483,8 @@
// Report form. See example at https://timetracker.anuko.com/report.php
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Esporta',
+// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
'form.report.assign_to_invoice' => 'Assegna alla fattura',
// TODO: translate the following.
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -533,8 +499,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Numero fattura',
'form.invoice.person' => 'Persona',
@@ -556,6 +522,8 @@
'form.tasks.inactive_tasks' => 'Compiti inattivi',
// Users form. See example at https://timetracker.anuko.com/users.php
+// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
'form.users.uncompleted_entry' => 'Questo utente ha un record temporale incompleto',
'form.users.role' => 'Ruolo',
'form.users.manager' => 'Manager',
@@ -614,14 +582,20 @@
'form.group_edit.type_duration' => 'durata',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
'form.group_edit.uncompleted_indicators' => 'Indicatori incompleti',
// TODO: translate the following.
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -629,7 +603,7 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'A',
'form.mail.report_subject' => 'Rapporto Time Tracker',
-'form.mail.footer' => 'Anuko Time Tracker è un sistema semplice e open source per registrare i tempi di lavoro. Visita www.anuko.com per maggiori informazioni.',
+'form.mail.footer' => 'Anuko Time Tracker è un sistema open source per registrare i tempi di lavoro. Visita www.anuko.com per maggiori informazioni.',
'form.mail.report_sent' => 'Rapporto inviato.',
'form.mail.invoice_sent' => 'Fattura inviata.',
@@ -686,21 +660,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/ja.lang.php b/WEB-INF/resources/ja.lang.php
index 26d222ebd..0de6e88ea 100644
--- a/WEB-INF/resources/ja.lang.php
+++ b/WEB-INF/resources/ja.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => '時間',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'レãƒãƒ¼ãƒˆ',
@@ -63,7 +41,6 @@
'menu.users' => 'ユーザー',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
// 'menu.export' => 'Export',
'menu.clients' => 'クライアント',
'menu.options' => 'オプション',
@@ -97,6 +74,9 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
'error.auth' => '䏿£ç¢ºãªãƒã‚°ã‚¤ãƒ³ã‚ã‚‹ã„ã¯ãƒ‘スワードãŒä¸æ£ç¢ºã§ã™ã€‚',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'ã“ã®ãƒã‚°ã‚¤ãƒ³ã¨é–¢é€£ã•れãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯æ—¢ã«å˜åœ¨ã—ã¾ã™ã€‚',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -125,7 +105,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -157,9 +136,11 @@
'button.import' => 'ãƒãƒ¼ãƒ ã®ã‚¤ãƒ³ãƒãƒ¼ãƒˆ', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -224,6 +205,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'è˜åˆ¥å',
'label.language' => '言語',
// TODO: translate the following.
@@ -245,11 +227,6 @@
'label.ldap_hint' => '下記ã®ãƒ•ィールドã«ã‚ãªãŸã®Windowsã®ãƒã‚°ã‚¤ãƒ³IDã¨ãƒ‘スワードを入力ã—ã¦ãã ã•ã„。',
'label.required_fields' => '* å¿…é ˆã®ãƒ•ィールド',
'label.on_behalf' => 'を代表ã—ã¦',
-// TODO: translate all 3 roles properly, see https://www.anuko.com/time_tracker/user_guide/user_accounts.htm
-// This may require different terms for role_manager and role_comanager.
-'label.role_manager' => '(管ç†è€…)',
-'label.role_comanager' => '(å…±åŒç®¡ç†è€…)',
-// 'label.role_admin' => '(administrator)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -274,9 +251,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => '全体ã ã‘',
@@ -293,20 +270,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -320,9 +285,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'ãƒã‚°ã‚¤ãƒ³',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'ãƒãƒ¼ãƒ ', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'ãƒãƒ¼ãƒ ã®å‰Šé™¤', // TODO: change "team" to "group".
@@ -334,6 +300,7 @@
'title.delete_time_record' => '時間レコードã®å‰Šé™¤',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -419,22 +386,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -464,7 +415,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -475,16 +425,26 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'パスワードを忘れã¾ã—ãŸã‹ï¼Ÿ',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'é€ä¿¡ã—ãŸãƒ‘スワードã®åˆæœŸåŒ–ã®è¦æ±‚。', // TODO: add "by email" to match the English string.
'form.reset_password.email_subject' => 'Anuko Time Trackerã®ãƒ‘スワードã®åˆæœŸåŒ–ã®è¦æ±‚',
// TODO: translate the ending of this string.
-// TODO: English string has changed. "from IP added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Older translation is below.
-// 'form.reset_password.email_body' => "尊敬ãªã‚‹ãŠå®¢æ§˜ã€\n\n誰ã‹ã‚‰ï¼ˆå¤šåˆ†ã‚ãªãŸï¼‰ã‚ãªãŸã®Anuko Time Trackerã®ãƒ‘スワードã®åˆæœŸåŒ–ãŒè¦æ±‚ã•れã¾ã—ãŸã€‚ã‚ãªãŸã®ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ã‚’åˆæœŸåŒ–ã—よã†ã¨ã“ã®ãƒªãƒ³ã‚¯ã‚’押ã—ã¦ãã ã•ã„。\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "尊敬ãªã‚‹ãŠå®¢æ§˜ã€\n\n誰ã‹ã‚‰ï¼ˆå¤šåˆ†ã‚ãªãŸï¼‰ã‚ãªãŸã®Anuko Time Trackerã®ãƒ‘スワードã®åˆæœŸåŒ–ãŒè¦æ±‚ã•れã¾ã—ãŸã€‚ã‚ãªãŸã®ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ã‚’åˆæœŸåŒ–ã—よã†ã¨ã“ã®ãƒªãƒ³ã‚¯ã‚’押ã—ã¦ãã ã•ã„。\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
@@ -523,10 +483,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => '時間期間ã®é¸æŠž',
'form.reports.set_period' => 'ã‚ã‚‹ã„ã¯æ—¥ä»˜ã‚’è¨å®š',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'フィールドã®è¡¨ç¤º',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => '次ã®ã‚ˆã†ã«ã‚°ãƒ«ãƒ¼ãƒ—化',
'form.reports.group_by_no' => '--- ã‚°ãƒ«ãƒ¼ãƒ—ã®æ©Ÿèƒ½ãŒã‚りã¾ã›ã‚“ ---',
'form.reports.group_by_date' => '日付',
@@ -541,6 +504,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => '輸出ã™ã‚‹', // TODO: is this correct?
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -554,8 +518,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'é€ã‚Šçжã®ç•ªå·',
'form.invoice.person' => '個人',
@@ -581,6 +545,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => '役割', // TODO: is this correct?
'form.users.manager' => '管ç†è€…',
@@ -642,13 +607,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -657,7 +628,7 @@
'form.mail.to' => 'ã¾ã§',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'é€ä¿¡ã—ãŸé€ã‚ŠçŠ¶ã€‚',
@@ -715,21 +686,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/ko.lang.php b/WEB-INF/resources/ko.lang.php
index fbfd6794b..fcbe14d24 100644
--- a/WEB-INF/resources/ko.lang.php
+++ b/WEB-INF/resources/ko.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => '시간',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'ë³´ê³ ì„œ',
@@ -63,7 +41,6 @@
'menu.users' => '사용ìž',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
// 'menu.export' => 'Export',
'menu.clients' => 'í´ë¼ì´ì–¸íЏ',
'menu.options' => '옵션',
@@ -97,6 +74,9 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
'error.auth' => 'ë¶€ì •í™•í•œ ë¡œê·¸ì¸ í˜¹ì€ ì•”í˜¸ê°€ 틀립니다.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => '본 로그ì¸ê³¼ ì—°ê³„ëœ ì‚¬ìš©ìžê°€ ì´ë¯¸ 있습니다.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -124,7 +104,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -156,9 +135,11 @@
'button.import' => '팀 ìž„í¬íЏ', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -223,6 +204,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ì‹ë³„ìž',
'label.language' => '언어',
// TODO: translate the following.
@@ -244,11 +226,6 @@
'label.ldap_hint' => 'ì•„ëž˜ì˜ í•„ë“œë“¤ì—서 Windows ë¡œê·¸ì¸ ë° ì•”í˜¸ 를 ìž…ë ¥í•˜ì‹ì‹œì˜¤.',
'label.required_fields' => '* 필수 필드',
'label.on_behalf' => 'ì„ ëŒ€í‘œí•˜ì—¬',
-// TODO: translate all 3 roles properly, see https://www.anuko.com/time_tracker/user_guide/user_accounts.htm
-// This may require different terms for role_manager and role_comanager.
-'label.role_manager' => '(관리ìž)',
-'label.role_comanager' => '(ê³µë™ê´€ë¦¬ìž)',
-// 'label.role_admin' => '(administrator)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -274,9 +251,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'ì˜¤ì§ ì „ì²´ë§Œ',
@@ -293,20 +270,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -320,9 +285,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => '로그ì¸',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => '팀', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => '팀 ì‚ì œ', // TODO: change "team" to "group".
@@ -334,6 +300,7 @@
'title.delete_time_record' => '시간기ë¡ì„ ì‚ì œí•˜ê¸°',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -420,22 +387,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -468,7 +419,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -479,13 +429,23 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => '암호를 잊으셨습니까?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'ì†¡ì‹ í•œ 암호 ìž¬ì„¤ì • ìš”ì².', // TODO: add "by email" to match the English string.
'form.reset_password.email_subject' => 'Anuko Time Tracker 암호 ìž¬ì„¤ì • ìš”ì²',
// TODO: translate the following.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -521,10 +481,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => '시간 ê¸°ê°„ì„ ì„ íƒ',
'form.reports.set_period' => 'í˜¹ì€ ë‚ ì§œë¥¼ ì„¤ì •',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'í•„ë“œë“¤ì„ ë³´ê¸°',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => '다ìŒê²ƒì— ì˜í•œ 그룹화',
'form.reports.group_by_no' => '--- 그룹화ë˜ì§€ ì•ŠìŒ ---',
'form.reports.group_by_date' => 'ë‚ ì§œ',
@@ -539,6 +502,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'ìµìФí¬íЏ', // TODO: is this correct?
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -552,8 +516,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => '송장 번호',
'form.invoice.person' => 'ê°œì¸',
@@ -579,6 +543,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'ì§ìœ„', // TODO: is this correct? The term "role" describes user function, as in "team manager role".
'form.users.manager' => '관리ìž',
@@ -640,13 +605,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -655,7 +626,7 @@
'form.mail.to' => '까지', // TODO: is this correct? The meaning is that we send an email TO this person.
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'ì†¡ì‹ í•œ 송장.',
@@ -713,21 +684,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/nl.lang.php b/WEB-INF/resources/nl.lang.php
index 1705e2cd3..2ca444c0a 100644
--- a/WEB-INF/resources/nl.lang.php
+++ b/WEB-INF/resources/nl.lang.php
@@ -1,32 +1,9 @@
'Groep',
'menu.plugins' => 'Plugins',
'menu.time' => 'Tijden',
+'menu.puncher' => 'Prikklok',
'menu.week' => 'Week',
'menu.expenses' => 'Kosten',
'menu.reports' => 'Rapporten',
@@ -56,7 +34,6 @@
'menu.tasks' => 'Taken',
'menu.users' => 'Medewerkers',
'menu.groups' => 'Groepen',
-'menu.subgroups' => 'Subgroepen',
'menu.export' => 'Exporteren',
'menu.clients' => 'Klanten',
'menu.options' => 'Opties',
@@ -83,6 +60,8 @@
'error.report' => 'Kies rapport.',
'error.record' => 'Kies record.',
'error.auth' => 'Onjuiste inlognaam of wachtwoord.',
+'error.2fa_code' => 'Niet geldige 2FA code.',
+'error.weak_password' => 'Zwak wachtwoord.',
'error.user_exists' => 'Een gebruiker met deze inlognaam bestaat al.',
'error.object_exists' => 'Een object met deze naam bestaat al.',
'error.invoice_exists' => 'Dit nummer is al eens toegekend aan een factuur.',
@@ -105,7 +84,6 @@
'error.user_count' => 'Limiet op aantal gebruikers.',
'error.expired' => 'Verloop datum is bereikt.',
'error.file_storage' => 'Bestand server probleem.',
-'error.remote_work' => 'Werk op afstand server probleem.',
// Warning messages.
'warn.sure' => 'Ben je er zeker van?',
@@ -131,9 +109,11 @@
'button.export' => 'Groep exporteren',
'button.import' => 'Groep importeren',
'button.close' => 'Sluiten',
+'button.start' => 'Start',
'button.stop' => 'Stop',
'button.approve' => 'Goedkeuren',
'button.disapprove' => 'Afkeuren',
+'button.sync' => 'Sychroniseer',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.menu' => 'Menu',
@@ -188,6 +168,7 @@
'label.select_none' => 'Selecteer niets',
'label.day_view' => 'Dag overzicht',
'label.week_view' => 'Week overzicht',
+'label.puncher' => 'Prikklok',
'label.id' => 'ID',
'label.language' => 'Taal',
'label.decimal_mark' => 'Decimaal teken',
@@ -206,9 +187,6 @@
'label.ldap_hint' => 'Type uw Windows login en wachtwoord in de onderstaande velden.',
'label.required_fields' => '* - verplichte velden',
'label.on_behalf' => 'namens',
-'label.role_manager' => '(manager)',
-'label.role_comanager' => '(co-manager)',
-'label.role_admin' => '(beheerder)',
'label.page' => 'Pagina',
'label.condition' => 'Voorwaarde',
'label.yes' => 'ja',
@@ -230,9 +208,9 @@
'label.paid_status' => 'Status van betaling',
'label.paid' => 'Betaald',
'label.mark_paid' => 'Markeer als betaald',
-'label.week_menu' => 'Week menu',
'label.week_note' => 'Week aantekening',
'label.week_list' => 'Week overzicht',
+'label.weekends' => 'Weekeinden',
'label.work_units' => 'Werk eenheid',
'label.work_units_short' => 'Eenheid',
'label.totals_only' => 'Alleen totalen',
@@ -248,17 +226,8 @@
'label.attachments' => 'Bijlagen',
'label.files' => 'Bestanden',
'label.file' => 'Bestand',
-'label.image' => 'Afbeelding',
-'label.download' => 'Download',
'label.active_users' => 'Actieve medewerkers',
'label.inactive_users' => 'Inactieve medewerkers',
-'label.details' => 'Details',
-'label.budget' => 'Budget',
-'label.work' => 'Werk',
-'label.offer' => 'Aanbod',
-'label.contractor' => 'Aanbieder',
-'label.how_to_pay' => 'Betaalwijze',
-'label.moderator_comment' => 'Commentaar',
// Entity names.
'entity.time' => 'tijd',
@@ -269,8 +238,8 @@
'title.error' => 'Fout',
'title.success' => 'Succes',
'title.login' => 'Aanmelden',
+'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Groepen',
-'title.subgroups' => 'Subgroepen',
'title.add_group' => 'Groep toevoegen',
'title.edit_group' => 'Groep bewerken',
'title.delete_group' => 'Groep aan het verwijderen',
@@ -280,6 +249,7 @@
'title.edit_time_record' => 'Wijzigen tijdrecord',
'title.delete_time_record' => 'Verwijder tijdrecord',
'title.time_files' => 'Tijden bestanden',
+'title.puncher' => 'Prikklok',
'title.expenses' => 'Kosten',
'title.edit_expense' => 'Bewerk kosten artikel',
'title.delete_expense' => 'Verwijder kosten artikel',
@@ -355,22 +325,6 @@
'title.edit_file' => 'Bestand bewerken',
'title.delete_file' => 'Bestand verwijderen',
'title.download_file' => ' Bestand downloaden',
-'title.work' => 'Werk',
-'title.add_work' => 'Werk toevoegen',
-'title.edit_work' => 'Werk bewerken',
-'title.delete_work' => 'Werk verwijderen',
-'title.active_work' => 'Actief werk',
-'title.available_work' => 'Beschikbaar werk',
-'title.inactive_work' => 'Inactief werk',
-'title.pending_work' => 'Werk in afwachting van goedkeuring',
-'title.offer' => 'Aanbod',
-'title.add_offer' => 'Aanbieding toevoegen',
-'title.edit_offer' => 'Aanbieding bewerken',
-'title.delete_offer' => 'Aanbieding verwijderen',
-'title.active_offers' => 'Actieve aanbiedingen',
-'title.available_offers' => 'Beschikbare aanbiedingen',
-'title.inactive_offers' => 'Inactieve aanbiedingen',
-'title.pending_offers' => 'Aangeboden werk in afwachting van goedkeuring',
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -399,7 +353,6 @@
'dropdown.status_inactive' => 'inactief',
'dropdown.delete' => 'verwijderen',
'dropdown.do_not_delete' => 'niet verwijderen',
-'dropdown.pending_approval' => 'in afwachting van goedkeuring',
'dropdown.approved' => 'goedgekeurd',
'dropdown.not_approved' => 'afgekeurd',
'dropdown.paid' => 'betaald',
@@ -414,12 +367,20 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Wachtwoord vergeten?',
-'form.login.about' => 'Anuko Time Tracker is een eenvoudig en gemakkelijk te gebruiken open source tijdregistratiesysteem.',
+'form.login.about' => 'Anuko Time Tracker is een open source tijdregistratiesysteem.',
+
+// Email subject and body for two-factor authentication.
+'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+'email.2fa_code.body' => "Beste gebruiker,\n\nJouw two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+'form.2fa.hint' => 'Je kunt je 2FA code vinden in een email die aan je is verstuurd en hier invullen.',
+'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Het verzoek om het wachtwoord te herstellen is verzonden per email.',
'form.reset_password.email_subject' => 'Anuko Time Tracker wachtwoord herstel verzoek',
-'form.reset_password.email_body' => "Geachte medewerker,\n\nIemand, met IP adres %s, heeft verzocht uw wachtwoord in Anuko Time Tracker te herstellen. Klik op deze link als u uw wachtwoord wil wijzigen.\n\n%s\n\nAnuko Time Tracker is een eenvoudig en gemakkelijk te gebruiken open source tijdregistratiesysteem. Bezoek https://www.anuko.com voor meer informatie.\n\n",
+'form.reset_password.email_body' => "Beste gebruiker,\n\nIemand, met IP adres %s, heeft verzocht uw wachtwoord in Anuko Time Tracker te herstellen. Klik op deze link als u uw wachtwoord wil wijzigen.\n\n%s\n\nAnuko Time Tracker is een open source tijdregistratiesysteem. Bezoek https://www.anuko.com voor meer informatie.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Voer het nieuwe wachtwoord in en klik op Bewaren.',
@@ -451,9 +412,11 @@
'form.reports.include_pending' => 'in afwachting',
'form.reports.select_period' => 'Kies periode',
'form.reports.set_period' => 'of stel datums in',
+'form.reports.note_containing' => 'Notitie bevat',
'form.reports.show_fields' => 'Toon velden',
'form.reports.time_fields' => 'Tijd velden',
'form.reports.user_fields' => 'Medewerker velden',
+'form.reports.project_fields' => 'Project velden',
'form.reports.group_by' => 'Groeperen op',
'form.reports.group_by_no' => '--- niet groeperen ---',
'form.reports.group_by_date' => 'datum',
@@ -465,6 +428,7 @@
// Report form. See example at https://timetracker.anuko.com/report.php
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exporteer',
+'form.report.per_hour' => 'Per uur',
'form.report.assign_to_invoice' => 'Voeg toe aan factuur',
'form.report.assign_to_timesheet' => 'Wijs toe aan tijdenoverzicht',
@@ -476,8 +440,8 @@
'form.templates.active_templates' => 'Actieve sjablonen',
'form.templates.inactive_templates' => 'Inactieve sjablonen',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Factuur nummer',
'form.invoice.person' => 'Medewerker',
@@ -499,6 +463,7 @@
'form.tasks.inactive_tasks' => 'Inactieve taken',
// Users form. See example at https://timetracker.anuko.com/users.php
+'form.users.uncompleted_entry_today' => 'Gebruiker heeft vandaag een tijd ingevoerd die niet compleet is',
'form.users.uncompleted_entry' => 'Gebruiker heeft tijd ingevoerd die niet compleet is',
'form.users.role' => 'Rol',
'form.users.manager' => 'Manager',
@@ -553,20 +518,25 @@
'form.group_edit.type_start_finish' => 'begin en einde',
'form.group_edit.type_duration' => 'duur',
'form.group_edit.punch_mode' => 'Start/stop modus',
+'form.group_edit.one_uncompleted' => 'Één niet-volledige registratie toestaan',
'form.group_edit.allow_overlap' => 'Sta overlapping van tijden toe',
'form.group_edit.future_entries' => 'Toevoegingen toestaan in de toekomst',
'form.group_edit.uncompleted_indicators' => 'Onvolledige indicatoren',
'form.group_edit.confirm_save' => 'Bevestigen dat je wilt opslaan',
-'form.group_edit.allow_ip' => 'Toegestane IP adressen',
'form.group_edit.advanced_settings' => 'Geavanceerde instellingen',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+'form.group_advanced_edit.allow_ip' => 'Toegestane IP adressen',
+'form.group_advanced_edit.password_complexity' => 'Wachtwoord complexiteit',
+'form.group_advanced_edit.2fa' => 'Two Factor Authentication (2FA)',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
'form.group_delete.hint' => 'Bent u er zeker van dat u de hele groep wilt verwijderen?',
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Aan',
'form.mail.report_subject' => 'Time Tracker rapport',
-'form.mail.footer' => 'Anuko Time Tracker is een eenvoudig en gemakkelijk te gebruiken open source tijdregistratiesysteem. Bezoek www.anuko.com voor meer informatie.',
+'form.mail.footer' => 'Anuko Time Tracker is een open source tijdregistratiesysteem. Bezoek www.anuko.com voor meer informatie.',
'form.mail.report_sent' => 'Rapport is verzonden.',
'form.mail.invoice_sent' => 'Factuur is verzonden.',
@@ -618,20 +588,8 @@
// Display Options form. See example at https://timetracker.anuko.com/display_options.php.
'form.display_options.note_on_separate_row' => 'Notitie in aparte kolom', // Translator (Henk) comment: "kolom is the right word in Dutch."
'form.display_options.not_complete_days' => 'Niet complete dagen',
+'form.display_options.inactive_projects' => 'Niet actieve projecten',
+'form.display_options.cost_per_hour' => 'Kosten per uur',
'form.display_options.custom_css' => 'Aangepaste CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-'work.error.work_not_available' => 'Werk onderdeel is niet beschikbaar.',
-'work.error.offer_not_available' => 'Aanbod is niet beschikbaar.',
-'work.type.one_time' => 'eenmalig',
-'work.type.ongoing' => 'doorlopend',
-'work.label.own_work' => 'Eigen werk',
-'work.label.own_offers' => 'Eigen aanbod',
-'work.label.offers' => 'Aanbiedingen',
-'work.button.send_message' => 'Verstuur bericht',
-'work.button.make_offer' => 'maak aanbieding',
-'work.button.accept' => 'Accepteer',
-'work.button.decline' => 'Weiger',
-'work.title.send_message' => 'Bericht wordt verstuurd',
-'work.msg.message_sent' => 'Bericht is verstuurd.',
+'form.display_options.custom_translation' => 'Maatwerk vertaling',
);
diff --git a/WEB-INF/resources/no.lang.php b/WEB-INF/resources/no.lang.php
index 81aff4489..720f71f34 100644
--- a/WEB-INF/resources/no.lang.php
+++ b/WEB-INF/resources/no.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Tid',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Rapporter',
@@ -64,7 +42,6 @@
'menu.users' => 'Brukere',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Eksport',
'menu.clients' => 'Klienter',
'menu.options' => 'Opsjoner',
@@ -98,6 +75,9 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
'error.auth' => 'Feil brukernavn eller passord.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Bruker med et slikt brukernavn eksisterer allerede.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -125,7 +105,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -156,9 +135,11 @@
'button.import' => 'Importer team', // TODO: replace "team" with "group".
'button.close' => 'Lukk',
// TODO: translate the following.
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -224,6 +205,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Språk',
// TODO: translate the following.
@@ -246,9 +228,6 @@
'label.required_fields' => '* obligatoriske felt',
'label.on_behalf' => 'på vegne av',
// TODO: translate the following.
-// 'label.role_manager' => '(manager)',
-// 'label.role_comanager' => '(co-manager)',
-// 'label.role_admin' => '(administrator)',
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
// 'label.yes' => 'yes',
@@ -272,9 +251,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
// 'label.totals_only' => 'Totals only',
@@ -290,20 +269,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -317,9 +284,9 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'Innlogging',
-// TODO: translate the following.
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
// 'title.groups' => 'Groups',
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'Slett team', // TODO: change "team" to "group".
@@ -331,6 +298,7 @@
'title.delete_time_record' => 'Slett tids oppføringen',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -416,22 +384,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -464,7 +416,6 @@
// TODO: translate the following.
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -474,14 +425,26 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Glemt passordet?',
+ // TODO: re-translate form.login.about as it has changed.
+ // 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
'form.login.about' => 'Anuko Time Tracker er et enkelt, brukervennlig tidsregistreringssystem basert på åpen kildekode.',
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
+
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
// TODO: translate the following.
// 'form.reset_password.message' => 'Password reset request sent by email.',
// 'form.reset_password.email_subject' => 'Anuko Time Tracker password reset request',
-// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
'form.reset_password.email_body' => "Kjære bruker,\n\nNoen, IP %s, bad om å få ditt Anuko Time Tracker password resatt. Vær vennlig å besøk denne lenken dersom du ønsker at passordet ditt skal resettes.\n\n%s\n\nAnuko Time Tracker er et enkelt og brukervennlig system for tidsregistrering basert på åpen kildekode. Les mer på https://www.anuko.com.\n\n",
@@ -520,10 +483,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Velg tidsperiode',
'form.reports.set_period' => 'eller sett dato',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Vis feltene',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
// 'form.reports.group_by' => 'Group by',
// 'form.reports.group_by_no' => '--- no grouping ---',
'form.reports.group_by_date' => 'dato',
@@ -537,6 +503,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Eksporter',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -550,8 +517,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Fakturanummer',
'form.invoice.person' => 'Person',
@@ -577,6 +544,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Rolle',
// TODO: translate the following.
@@ -639,13 +607,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -654,7 +628,7 @@
'form.mail.to' => 'Til',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
// 'form.mail.invoice_sent' => 'Invoice sent.',
@@ -712,21 +686,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/pl.lang.php b/WEB-INF/resources/pl.lang.php
index 2000584e9..69dddf311 100644
--- a/WEB-INF/resources/pl.lang.php
+++ b/WEB-INF/resources/pl.lang.php
@@ -1,32 +1,9 @@
'Moduły',
'menu.time' => 'Czas',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Wydatki',
'menu.reports' => 'Raporty',
@@ -61,7 +39,6 @@
'menu.users' => 'Użytkownicy',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Eksport',
'menu.clients' => 'Klienci',
'menu.options' => 'Opcje',
@@ -93,6 +70,9 @@
// TODO: translate the following.
// 'error.record' => 'Select record.',
'error.auth' => 'Błędny login lub hasło.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Użytkownik o takiej nazwie już istnieje.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -122,7 +102,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -150,10 +129,13 @@
'button.export' => 'Eksportuj zespół', // TODO: replace "team" with "group".
'button.import' => 'Importuj zespół', // TODO: replace "team" with "group".
'button.close' => 'Zamknij',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'Zatrzymaj',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -215,6 +197,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Język',
'label.decimal_mark' => 'Znak dziesiętny',
@@ -233,9 +216,6 @@
'label.ldap_hint' => 'Wpisz swoją nazwę użytkownika Windows i hasło w polach poniżej.',
'label.required_fields' => '* - pola wymagane',
'label.on_behalf' => 'w imieniu',
-'label.role_manager' => '(Manager)',
-'label.role_comanager' => '(Co-manager)',
-'label.role_admin' => '(Administrator)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -260,9 +240,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Tylko sumy',
@@ -279,21 +259,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'Aktywni użytkownicy',
'label.inactive_users' => 'Nieaktywni użytkownicy',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -307,9 +274,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'Logowanie',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Zespoły', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
'title.edit_group' => 'Edytowanie zespołu', // TODO: change "team" to "group".
'title.delete_group' => 'Usuwanie zespołu', // TODO: change "team" to "group".
@@ -320,6 +288,7 @@
'title.delete_time_record' => 'Usuwanie wpisu',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Wydatki',
'title.edit_expense' => 'Edytowanie wpisu',
'title.delete_expense' => 'Usuwanie wpisu',
@@ -400,22 +369,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -448,7 +401,6 @@
'dropdown.delete' => 'usuń',
'dropdown.do_not_delete' => 'nie usuwaj',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -463,15 +415,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Nie pamiętasz hasła?',
-'form.login.about' => 'Anuko Time Tracker jest prostym, łatwym w użyciu, otwartoźródłowym systemem śledzenia czasu.',
+'form.login.about' => 'Anuko Time Tracker jest otwartoźródłowym systemem śledzenia czasu.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Instrukcje zmiany hasła zostały wysłane na adres e-mail połączony z kontem.',
'form.reset_password.email_subject' => 'Anuko Time Tracker - żądanie zmiany hasła',
// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Drogi Użytkowniku,\n\nktoś, IP %s, poprosił o zmianę hasła w aplikacji Anuko Time Tracker. Aby ustawić nowe hasło, proszę kliknąć na poniższy link lub go skopiować i otworzyć w oknie przeglądarki WWW.\n\n%s\n\nJeśli to nie Ty poprosiłeś o zmianę hasła, zignoruj tą wiadomość.\n\nAnuko Time Tracker jest prostym, łatwym w użyciu, otwartoźródłowym systemem do śledzenia czasu. Odwiedź https://www.anuko.com aby uzyskać więcej informacji.\n\n",
+'form.reset_password.email_body' => "Drogi Użytkowniku,\n\nktoś, IP %s, poprosił o zmianę hasła w aplikacji Anuko Time Tracker. Aby ustawić nowe hasło, proszę kliknąć na poniższy link lub go skopiować i otworzyć w oknie przeglądarki WWW.\n\n%s\n\nJeśli to nie Ty poprosiłeś o zmianę hasła, zignoruj tą wiadomość.\n\nAnuko Time Tracker jest otwartoźródłowym systemem do śledzenia czasu. Odwiedź https://www.anuko.com aby uzyskać więcej informacji.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Wpisz nowe hasło i kliknij Zapisz.',
@@ -506,10 +468,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Wybierz okres',
'form.reports.set_period' => 'lub ustaw daty',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Pokaż pola',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Grupowanie wg',
'form.reports.group_by_no' => '--- bez grupowania ---',
'form.reports.group_by_date' => 'daty',
@@ -522,6 +487,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Eksport',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -535,8 +501,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Numer faktury',
'form.invoice.person' => 'Osoba',
@@ -560,6 +526,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+ // 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Rola',
'form.users.manager' => 'Manager',
@@ -620,13 +587,19 @@
'form.group_edit.type_duration' => 'czas trwania',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -634,7 +607,7 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Do',
'form.mail.report_subject' => 'Raport Time Tracker',
-'form.mail.footer' => 'Anuko Time Tracker jest prostym, łatwym w użyciu, otwartoźródłowym systemem śledzenia czasu. Odwiedź www.anuko.com, aby uzyskać więcej informacji.',
+'form.mail.footer' => 'Anuko Time Tracker jest otwartoźródłowym systemem śledzenia czasu. Odwiedź www.anuko.com, aby uzyskać więcej informacji.',
'form.mail.report_sent' => 'Wysłano raport',
'form.mail.invoice_sent' => 'Wysłano fakturę',
@@ -692,21 +665,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/pt-br.lang.php b/WEB-INF/resources/pt-br.lang.php
index 61afec796..c9a4ad998 100644
--- a/WEB-INF/resources/pt-br.lang.php
+++ b/WEB-INF/resources/pt-br.lang.php
@@ -1,35 +1,12 @@
'Logout',
'menu.forum' => 'Fórum',
'menu.help' => 'Ajuda',
-// TODO: translate the following.
-// 'menu.register' => 'Register',
+'menu.register' => 'Registro',
'menu.profile' => 'Perfil',
-// TODO: translate the following.
-// 'menu.group' => 'Group',
+'menu.group' => 'Grupo',
'menu.plugins' => 'Plugins',
'menu.time' => 'Tempo',
-// TODO: translate the following.
-// 'menu.week' => 'Week',
-'menu.expenses' => 'Gastos',
+'menu.puncher' => 'Punch',
+'menu.week' => 'Semana',
+'menu.expenses' => 'Despesas',
'menu.reports' => 'Relatórios',
-// TODO: translate the following.
-// 'menu.timesheets' => 'Timesheets',
+'menu.timesheets' => 'Planilha de horas',
'menu.charts' => 'Gráficos',
'menu.projects' => 'Projetos',
'menu.tasks' => 'Tarefas',
'menu.users' => 'Usuários',
-// TODO: translate the following.
-// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
+'menu.groups' => 'Grupos',
'menu.export' => 'Exportar',
'menu.clients' => 'Clientes',
'menu.options' => 'Opções',
@@ -76,59 +48,50 @@
'error.access_denied' => 'Acesso negado.',
'error.sys' => 'Erro no sistema.',
'error.db' => 'Erro no banco de dados.',
-// TODO: translate the following.
-// 'error.registered_recently' => 'Registered recently.',
-// 'error.feature_disabled' => 'Feature is disabled.',
+'error.registered_recently' => 'Registrado recentemente.',
+'error.feature_disabled' => 'Recurso desabilitado.',
'error.field' => 'Dados incorretos "{0}".',
'error.empty' => 'Campo "{0}" está vazio.',
'error.not_equal' => 'Campo "{0}" é diferente do campo "{1}".',
-// TODO: translate the following.
-// 'error.interval' => 'Field "{0}" must be greater than "{1}".',
+'error.interval' => 'Campo "{0}" precisa ser maior que "{1}".',
'error.project' => 'Selecione projeto.',
'error.task' => 'Selecione tarefa.',
'error.client' => 'Selecione cliente.',
'error.report' => 'Selecione relatório.',
-// TODO: translate the following.
-// 'error.record' => 'Select record.',
+'error.record' => 'Selecione o registro.',
'error.auth' => 'Usuário ou senha incorretos.',
-'error.user_exists' => 'Já existe usuário com este login.',
// TODO: translate the following.
-// 'error.object_exists' => 'Object with this name already exists.',
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
+'error.user_exists' => 'Já existe usuário com este login.',
+'error.object_exists' => 'Já existe um objeto com este nome.',
'error.invoice_exists' => 'Já existe fatura com este número.',
-// TODO: translate the following.
-// 'error.role_exists' => 'Role with this rank already exists.',
+'error.role_exists' => 'Já existe uma função com este rank.',
'error.no_invoiceable_items' => 'Não há items faturáveis.',
-// TODO: translate the following.
-// 'error.no_records' => 'There are no records.',
+'error.no_records' => 'Não há registros.',
'error.no_login' => 'Não há usuário com este login.',
-'error.no_groups' => 'Sua base de dados está vazia. Entre como admin e crie uma equipe nova.', // TODO: replace "team" with "group".
+'error.no_groups' => 'Sua base de dados está vazia. Entre como admin e crie um grupo novo.',
'error.upload' => 'Erro no envio do arquivo.',
-'error.range_locked' => 'PerÃodo está bloqueado.',
-'error.mail_send' => 'Erro enviando o e-mail.',
-// TODO: improve the translation above by adding MAIL_SMTP_DEBUG part.
-// 'error.mail_send' => 'Error sending mail. Use MAIL_SMTP_DEBUG for diagnostics.',
+'error.range_locked' => 'PerÃodo bloqueado.',
+'error.mail_send' => 'Erro ao enviar e-mail. Use MAIL_SMTP_DEBUG para diagnósticos.', // "Use" means the same in pt-br as in en.
'error.no_email' => 'Não há e-mail associado a este login.',
'error.uncompleted_exists' => 'Entrada incompleta existente. Feche ou remova-a.',
'error.goto_uncompleted' => 'Ir até a entrada incompleta.',
'error.overlap' => 'O intervalo se sobrepõe com entradas já existentes.',
'error.future_date' => 'Data é no futuro.',
-// TODO: translate the following.
-// 'error.xml' => 'Error in XML file at line %d: %s.',
-// 'error.cannot_import' => 'Cannot import: %s.',
-// 'error.format' => 'Invalid file format.',
-// 'error.user_count' => 'Limit on user count.',
-// 'error.expired' => 'Expiration date reached.',
-// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
+'error.xml' => 'Erro no arquivo XML, linha line %d: %s.',
+'error.cannot_import' => 'Não foi possÃvel importar: %s.',
+'error.format' => 'Formato de arquivo inválido.',
+'error.user_count' => 'Limite na contagem de usuários.',
+'error.expired' => 'Data de expiração atingida.',
+'error.file_storage' => 'Erro relacionado ao servidor de armazenamento de arquivos.',
// Warning messages.
-// TODO: translate the following.
-// 'warn.sure' => 'Are you sure?',
-// 'warn.confirm_save' => 'Date has changed. Confirm saving, not copying this item.',
+'warn.sure' => 'Tem certeza?',
+'warn.confirm_save' => 'A data mudou. Confirme salvando, não copiando este item.',
// Success messages.
-// TODO: translate the following.
-// 'msg.success' => 'Operation completed successfully.',
+'msg.success' => 'Operação concluÃda com sucesso.',
// Labels for buttons.
'button.login' => 'Login',
@@ -143,19 +106,20 @@
'button.reset_password' => 'Resetar senha',
'button.send' => 'Enviar',
'button.send_by_email' => 'Enviar por e-mail',
-'button.create_group' => 'Criar equipe', // TODO: replace "team" with "group".
-'button.export' => 'Exportar equipe', // TODO: replace "team" with "group".
-'button.import' => 'Importar equipe', // TODO: replace "team" with "group".
+'button.create_group' => 'Criar grupo',
+'button.export' => 'Exportar grupo',
+'button.import' => 'Importar grupo',
'button.close' => 'Fechar',
+'button.start' => 'Iniciar',
'button.stop' => 'Parar',
+'button.approve' => 'Aprovar',
+'button.disapprove' => 'Desaprovar',
// TODO: translate the following.
-// 'button.approve' => 'Approve',
-// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
-// TODO: translate the following.
-// 'label.menu' => 'Menu',
-'label.group_name' => 'Nome da equipe', // TODO: replace "team" with "group".
+'label.menu' => 'Menu',
+'label.group_name' => 'Nome do grupo',
'label.address' => 'Endereço',
'label.currency' => 'Moeda',
'label.manager_name' => 'Nome do gerente',
@@ -167,18 +131,16 @@
'label.confirm_password' => 'Confirme a senha',
'label.email' => 'E-mail',
'label.cc' => 'Cc',
-// TODO: translate the following.
-// 'label.bcc' => 'Bcc',
+'label.bcc' => 'Bcc',
'label.subject' => 'Assunto',
'label.date' => 'Data',
'label.start_date' => 'Data inicial',
'label.end_date' => 'Data final',
'label.user' => 'Usuário',
'label.users' => 'Usuários',
-// TODO: translate the following.
-// 'label.group' => 'Group',
-// 'label.subgroups' => 'Subgroups',
-// 'label.roles' => 'Roles',
+'label.group' => 'Grupo',
+'label.subgroups' => 'Subgrupos',
+'label.roles' => 'Funções',
'label.client' => 'Cliente',
'label.clients' => 'Clientes',
'label.option' => 'Opção',
@@ -192,16 +154,13 @@
'label.finish' => 'Fim',
'label.duration' => 'Duração',
'label.note' => 'Anotação',
-// TODO: translate the following.
-// 'label.notes' => 'Notes',
+'label.notes' => 'Anotações',
'label.item' => 'Item',
'label.cost' => 'Custo',
-// TODO: translate the following.
-// 'label.ip' => 'IP',
+'label.ip' => 'IP',
'label.day_total' => 'Total diário',
'label.week_total' => 'Total semanal',
-// TODO: translate the following.
-// 'label.month_total' => 'Month total',
+'label.month_total' => 'Total mensal',
'label.today' => 'Hoje',
'label.view' => 'Ver',
'label.edit' => 'Editar',
@@ -209,9 +168,9 @@
'label.configure' => 'Configurar',
'label.select_all' => 'Selecionar todos',
'label.select_none' => 'Desmarcar todos',
-// TODO: translate the following.
-// 'label.day_view' => 'Day view',
-// 'label.week_view' => 'Week view',
+'label.day_view' => 'Visão diária',
+'label.week_view' => 'Visão semanal',
+'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Idioma',
'label.decimal_mark' => 'Ponto decimal',
@@ -230,21 +189,15 @@
'label.ldap_hint' => 'Entre com o seu login do Windows e senha nos campos abaixo.',
'label.required_fields' => '* - campos obrigatórios',
'label.on_behalf' => 'em nome de',
-'label.role_manager' => '(gerente)',
-'label.role_comanager' => '(coordenador)',
-'label.role_admin' => '(administrador)',
'label.page' => 'Página',
-// TODO: translate the following.
-// 'label.condition' => 'Condition',
-// 'label.yes' => 'yes',
-// 'label.no' => 'no',
-// 'label.sort' => 'Sort',
+'label.condition' => 'Condição',
+'label.yes' => 'sim',
+'label.no' => 'não',
+'label.sort' => 'Ordenar',
// Labels for plugins (extensions to Time Tracker that provide additional features).
'label.custom_fields' => 'Campos personalizados',
-// Translate the following.
-// 'label.monthly_quotas' => 'Monthly quotas',
-// TODO: translate the following.
-// 'label.entity' => 'Entity',
+'label.monthly_quotas' => 'Cotas mensais',
+'label.entity' => 'Entidade',
'label.type' => 'Tipo',
'label.type_dropdown' => 'lista suspensa',
'label.type_text' => 'texto',
@@ -252,89 +205,71 @@
'label.fav_report' => 'Relatório favorito',
'label.schedule' => 'Agenda',
'label.what_is_it' => 'O que é?',
-// 'label.expense' => 'Expense',
-// 'label.quantity' => 'Quantity',
-// 'label.paid_status' => 'Paid status',
-// 'label.paid' => 'Paid',
-// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
-// 'label.week_note' => 'Week note',
-// 'label.week_list' => 'Week list',
-// 'label.work_units' => 'Work units',
-// 'label.work_units_short' => 'Units',
+'label.expense' => 'Despesa',
+'label.quantity' => 'Quantidade',
+'label.paid_status' => 'Status pago',
+'label.paid' => 'Pago',
+'label.mark_paid' => 'Marcar como pago',
+'label.week_note' => 'Anotação da semana',
+'label.week_list' => 'Lista da semana',
+// TODO: translate the following.
+// 'label.weekends' => 'Weekends',
+'label.work_units' => 'Unidades de trabalho',
+'label.work_units_short' => 'Unidades',
'label.totals_only' => 'Somente totais',
-// TODO: translate the following.
-// 'label.quota' => 'Quota',
-// 'label.timesheet' => 'Timesheet',
-// 'label.submitted' => 'Submitted',
-// 'label.approved' => 'Approved',
-// 'label.approval' => 'Report approval',
-// 'label.mark_approved' => 'Mark approved',
-// 'label.template' => 'Template',
-// 'label.bind_templates_with_projects' => 'Bind templates with projects',
-// 'label.prepopulate_note' => 'Prepopulate Note field',
-// 'label.attachments' => 'Attachments',
-// 'label.files' => 'Files',
-// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
+'label.quota' => 'Cota',
+'label.timesheet' => 'Planilha de horas',
+'label.submitted' => 'Enviado',
+'label.approved' => 'Aprovado',
+'label.approval' => 'Aprovação de relatório',
+'label.mark_approved' => 'Marcar como aprovado',
+'label.template' => 'Modelo',
+'label.bind_templates_with_projects' => 'Vincular modelos com projetos',
+'label.prepopulate_note' => 'Pré-preencher campo de anotação',
+'label.attachments' => 'Anexos',
+'label.files' => 'Arquivos',
+'label.file' => 'Arquivo',
'label.active_users' => 'Usuários ativos',
'label.inactive_users' => 'Usuários inativos',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
-// TODO: translate the following.
-// 'entity.time' => 'time',
-// 'entity.user' => 'user',
-// 'entity.project' => 'project',
+'entity.time' => 'tempo',
+'entity.user' => 'usuário',
+'entity.project' => 'projeto',
// Form titles.
'title.error' => 'Erro',
-// TODO: Translate the following.
-// 'title.success' => 'Success',
+'title.success' => 'Sucesso',
'title.login' => 'Login',
-'title.groups' => 'Equipes', // TODO: change "teams" to "groups".
-// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
-// 'title.add_group' => 'Adding Group',
-'title.edit_group' => 'Editando equipe', // TODO: change "team" to "group".
-'title.delete_group' => 'Apagando equipe', // TODO: change "team" to "group".
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
+'title.groups' => 'Grupos',
+'title.add_group' => 'Adicionando grupo',
+'title.edit_group' => 'Editando grupo',
+'title.delete_group' => 'Apagando grupo',
'title.reset_password' => 'Resetando a senha',
'title.change_password' => 'Alterando a senha',
'title.time' => 'Tempo',
'title.edit_time_record' => 'Editando entrada de hora',
'title.delete_time_record' => 'Apagando entrada de hora',
-// TODO: Translate the following.
-// 'title.time_files' => 'Time Record Files',
+'title.time_files' => 'Arquivos de registro de tempo',
+'title.puncher' => 'Puncher',
'title.expenses' => 'Gastos',
'title.edit_expense' => 'Editando item de gasto',
'title.delete_expense' => 'Apagando item de gasto',
-// TODO: translate the following.
-// 'title.expense_files' => 'Expense Item Files',
+'title.expense_files' => 'Arquivos de itens de despesas',
'title.reports' => 'Relatórios',
'title.report' => 'Report',
'title.send_report' => 'Enviando relatório',
-// TODO: Translate the following.
-// 'title.timesheets' => 'Timesheets',
-// 'title.timesheet' => 'Timesheet',
-// 'title.timesheet_files' => 'Timesheet Files',
+'title.timesheets' => 'Planilhas de horas',
+'title.timesheet' => 'Planilha de horas',
+'title.timesheet_files' => 'Arquivos de planilha de horas',
'title.invoice' => 'Fatura',
'title.send_invoice' => 'Enviando fatura',
'title.charts' => 'Gráficos',
'title.projects' => 'Projetos',
-// TODO: translate the following.
-// 'title.project_files' => 'Project Files',
+'title.project_files' => 'Arquivos do projeto',
'title.add_project' => 'Adicionando projeto',
'title.edit_project' => 'Editando projeto',
'title.delete_project' => 'Apagando projeto',
@@ -346,11 +281,10 @@
'title.add_user' => 'Adicionando usuário',
'title.edit_user' => 'Editando usuário',
'title.delete_user' => 'Apagando usuário',
-// TODO: translate the following.
-// 'title.roles' => 'Roles',
-// 'title.add_role' => 'Adding Role',
-// 'title.edit_role' => 'Editing Role',
-// 'title.delete_role' => 'Deleting Role',
+'title.roles' => 'Funções',
+'title.add_role' => 'Adicionando função',
+'title.edit_role' => 'Editando função',
+'title.delete_role' => 'Apagando função',
'title.clients' => 'Clientes',
'title.add_client' => 'Adicionando cliente',
'title.edit_client' => 'Editando cliente',
@@ -363,16 +297,14 @@
'title.add_notification' => 'Adicionando notificação',
'title.edit_notification' => 'Editando notificação',
'title.delete_notification' => 'Apagando notificação',
-// TODO: translate the following.
-// 'title.add_timesheet' => 'Adding Timesheet',
-// 'title.edit_timesheet' => 'Editing Timesheet',
-// 'title.delete_timesheet' => 'Deleting Timesheet',
-// 'title.monthly_quotas' => 'Monthly Quotas',
-'title.export' => 'Exportando dados de equipe', // TODO: replace "team" with "group".
-'title.import' => 'Importando dados de equipe', // TODO: replace "team" with "group".
+'title.add_timesheet' => 'Adicionando planilha de horas',
+'title.edit_timesheet' => 'Editando planilha de horas',
+'title.delete_timesheet' => 'Apagando planilha de horas',
+'title.monthly_quotas' => 'Cotas mensais',
+'title.export' => 'Exportando dados do grupo',
+'title.import' => 'Importando dados do grupo',
'title.options' => 'Opções',
-// TODO: translate the following.
-// 'title.display_options' => 'Display Options',
+'title.display_options' => 'Opções de exibição',
'title.profile' => 'Perfil',
'title.plugins' => 'Plugins',
'title.cf_custom_fields' => 'Campos personalizados',
@@ -384,41 +316,23 @@
'title.cf_edit_dropdown_option' => 'Editando opção',
'title.cf_delete_dropdown_option' => 'Apagando opção',
'title.locking' => 'Bloquear',
-// TODO: translate the following.
-// 'title.week_view' => 'Week View',
-// 'title.swap_roles' => 'Swapping Roles',
-// 'title.work_units' => 'Work Units',
-// 'title.templates' => 'Templates',
-// 'title.add_template' => 'Adding Template',
-// 'title.edit_template' => 'Editing Template',
-// 'title.delete_template' => 'Deleting Template',
-// 'title.edit_file' => 'Editing File',
-// 'title.delete_file' => 'Deleting File',
-// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
+'title.week_view' => 'Visão semanal',
+'title.swap_roles' => 'Alteração de funções',
+'title.work_units' => 'Unidades de trabalho',
+'title.templates' => 'Modelos',
+'title.add_template' => 'Adicionando modelo',
+'title.edit_template' => 'Editando modelo',
+'title.delete_template' => 'Apagando modelo',
+'title.edit_file' => 'Editando arquivo',
+'title.delete_file' => 'Apagando arquivo',
+'title.download_file' => 'Baixando arquivo',
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
'dropdown.all' => '--- todos ---',
'dropdown.no' => '--- não ---',
-// TODO: translate the following.
-// 'dropdown.current_day' => 'today',
-// 'dropdown.previous_day' => 'yesterday',
+'dropdown.current_day' => 'hoje',
+'dropdown.previous_day' => 'ontem',
'dropdown.selected_day' => 'dia',
'dropdown.current_week' => 'esta semana',
'dropdown.previous_week' => 'última semana',
@@ -427,8 +341,7 @@
'dropdown.previous_month' => 'último mês',
'dropdown.selected_month' => 'mês',
'dropdown.current_year' => 'este ano',
-// TODO: translate the following.
-// 'dropdown.previous_year' => 'previous year',
+'dropdown.previous_year' => 'último ano',
'dropdown.selected_year' => 'ano',
'dropdown.all_time' => 'todas as datas',
'dropdown.projects' => 'projetos',
@@ -436,20 +349,17 @@
'dropdown.clients' => 'clientes',
'dropdown.select' => '--- selecione ---',
'dropdown.select_invoice' => '--- selecione fatura ---',
-// TODO: translate the following.
-// 'dropdown.select_timesheet' => '--- select timesheet ---',
+'dropdown.select_timesheet' => '--- selecione planilha de horas ---',
'dropdown.status_active' => 'ativo',
'dropdown.status_inactive' => 'inativo',
'dropdown.delete' => 'apagar',
'dropdown.do_not_delete' => 'não apagar',
-// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
-// 'dropdown.approved' => 'approved',
-// 'dropdown.not_approved' => 'not approved',
-// 'dropdown.paid' => 'paid',
-// 'dropdown.not_paid' => 'not paid',
-// 'dropdown.ascending' => 'ascending',
-// 'dropdown.descending' => 'descending',
+'dropdown.approved' => 'aprovado',
+'dropdown.not_approved' => 'não aprovado',
+'dropdown.paid' => 'pago',
+'dropdown.not_paid' => 'não pago',
+'dropdown.ascending' => 'ascendente',
+'dropdown.descending' => 'descendente',
// Below is a section for strings that are used on individual forms. When a string is used only on one form it should be placed here.
// One exception is for closely related forms such as "Time" and "Editing Time Record" with similar controls. In such cases
@@ -458,15 +368,22 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Esqueceu a senha?',
-'form.login.about' => 'Anuko Time Tracker é um sistema, simples, de fácil uso, de código aberto, de rastreamento do tempo.',
+'form.login.about' => 'Anuko Time Tracker é um sistema de código aberto de rastreamento do tempo.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Pedido para resetar a senha enviado por e-mail.',
'form.reset_password.email_subject' => 'Pedido de alteração de senha no Anuko Time Tracker',
-// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
-// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Prezado usuário,\n\nAlguém, IP %s, solicitou o reset da sua senha do Anuko Time Tracker. Entre nete link para resetar a sua senha.\n\n%s\n\nAnuko Time Tracker é um sistema, simples, de fácil uso, de código abertois, de rastreamento do tempo. Visite https://www.anuko.com para mais informações.\n\n",
+'form.reset_password.email_body' => "Caro usuário,\n\nAlguém do IP %s solicitou a redefinição da senha do Anuko Time Tracker. Visite este link se quiser redefinir sua senha.\n\n%s\n\nAnuko Time Tracker é um sistema de rastreamento de apontamentos de código aberto. Visite https://www.anuko.com para obter mais informações.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Entre com a nova senha e clique em Salvar.',
@@ -475,36 +392,36 @@
'form.time.duration_format' => '(hh:mm ou 0.0h)',
'form.time.billable' => 'Faturável',
'form.time.uncompleted' => 'Incompleta',
-// TODO: translate the following.
-// 'form.time.remaining_quota' => 'Remaining quota',
-// 'form.time.over_quota' => 'Over quota',
-// 'form.time.remaining_balance' => 'Remaining balance',
-// 'form.time.over_balance' => 'Over balance',
+'form.time.remaining_quota' => 'Cota restante',
+'form.time.over_quota' => 'Acima da cota',
+'form.time.remaining_balance' => 'Saldo restante',
+'form.time.over_balance' => 'Saldo excedente',
// Editing Time Record form. See example at https://timetracker.anuko.com/time_edit.php (get there by editing an uncompleted time record).
-'form.time_edit.uncompleted' => 'Eesta entrada foi salva somente com hora de inÃcio. Não é um erro.',
+'form.time_edit.uncompleted' => 'Esta entrada foi salva somente com hora de inÃcio. Não é um erro.',
// Week view form. See example at https://timetracker.anuko.com/week.php.
-// TODO: translate the following.
-// 'form.week.new_entry' => 'New entry',
+'form.week.new_entry' => 'Nova entrada',
-// Reports form. See example at https://timetracker.anuko.com/reports.php
+// Reports form. See example at https://timetracker.anuko.com/reports.php.
'form.reports.save_as_favorite' => 'Guardar como favorito',
'form.reports.confirm_delete' => 'Tem certeza que deseja remover este relatório dos favoritos?',
'form.reports.include_billable' => 'faturável',
'form.reports.include_not_billable' => 'não faturável',
'form.reports.include_invoiced' => 'faturado',
'form.reports.include_not_invoiced' => 'não faturado',
-// TODO: translate the following.
-// 'form.reports.include_assigned' => 'assigned',
-// 'form.reports.include_not_assigned' => 'not assigned',
-// 'form.reports.include_pending' => 'pending',
+'form.reports.include_assigned' => 'atribuÃdo',
+'form.reports.include_not_assigned' => 'não atribuÃdo',
+'form.reports.include_pending' => 'pendente',
'form.reports.select_period' => 'Selecione o perÃodo de tempo',
'form.reports.set_period' => 'ou selecionar datas',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Exibir campos',
+'form.reports.time_fields' => 'Campos de tempo',
+'form.reports.user_fields' => 'Campos de usuário',
// TODO: translate the following.
-// 'form.reports.time_fields' => 'Time fields',
-// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Agrupar por',
'form.reports.group_by_no' => '--- sem agrupar ---',
'form.reports.group_by_date' => 'data',
@@ -517,94 +434,88 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exportar',
// TODO: translate the following.
-// 'form.report.assign_to_invoice' => 'Assign to invoice',
-// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
+// 'form.report.per_hour' => 'Per hour',
+'form.report.assign_to_invoice' => 'Atribuir a fatura',
+'form.report.assign_to_timesheet' => 'Atribuir a planilha de horas',
-// Timesheets form. See example at https://timetracker.anuko.com/timesheets.php
-// TODO: translate the following.
-// 'form.timesheets.active_timesheets' => 'Active Timesheets',
-// 'form.timesheets.inactive_timesheets' => 'Inactive Timesheets',
+// Timesheets form. See example at https://timetracker.anuko.com/timesheets.php.
+'form.timesheets.active_timesheets' => 'Planilhas de horas ativas',
+'form.timesheets.inactive_timesheets' => 'Planilhas de horas inativas',
-// Templates form. See example at https://timetracker.anuko.com/templates.php
-// TODO: translate the following.
-// 'form.templates.active_templates' => 'Active Templates',
-// 'form.templates.inactive_templates' => 'Inactive Templates',
+// Templates form. See example at https://timetracker.anuko.com/templates.php.
+'form.templates.active_templates' => 'Modelos ativos',
+'form.templates.inactive_templates' => 'Modelos inativos',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Número da fatura',
'form.invoice.person' => 'Pessoa',
-// Deleting Invoice form. See example at https://timetracker.anuko.com/invoice_delete.php
+// Deleting Invoice form. See example at https://timetracker.anuko.com/invoice_delete.php.
'form.invoice.invoice_to_delete' => 'Fatura a ser apagada',
'form.invoice.invoice_entries' => 'Entradas de fatura',
-// TODO: translate the following.
-// 'form.invoice.confirm_deleting_entries' => 'Please confirm deleting invoice entries from Time Tracker.',
+'form.invoice.confirm_deleting_entries' => 'Confirme a exclusão das entradas de fatura do Time Tracker.',
-// Charts form. See example at https://timetracker.anuko.com/charts.php
+// Charts form. See example at https://timetracker.anuko.com/charts.php.
'form.charts.interval' => 'Intervalo',
'form.charts.chart' => 'Gráfico',
-// Projects form. See example at https://timetracker.anuko.com/projects.php
+// Projects form. See example at https://timetracker.anuko.com/projects.php.
'form.projects.active_projects' => 'Projetos ativos',
'form.projects.inactive_projects' => 'Projetos inativos',
-// Tasks form. See example at https://timetracker.anuko.com/tasks.php
+// Tasks form. See example at https://timetracker.anuko.com/tasks.php.
'form.tasks.active_tasks' => 'Tarefas ativas',
'form.tasks.inactive_tasks' => 'Tarefas inativas',
-// Users form. See example at https://timetracker.anuko.com/users.php
+// Users form. See example at https://timetracker.anuko.com/users.php.
// TODO: translate the following.
-// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
-'form.users.role' => 'Papel',
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
+'form.users.uncompleted_entry' => 'O usuário tem uma entrada incompleta',
+'form.users.role' => 'Função',
'form.users.manager' => 'Gerente',
'form.users.comanager' => 'Coordenador',
'form.users.rate' => 'Honorário',
'form.users.default_rate' => 'Honorário padrão por hora',
-// Editing User form. See example at https://timetracker.anuko.com/user_edit.php
-// TODO: translate the following.
-// 'form.user_edit.swap_roles' => 'Swap roles',
+// Editing User form. See example at https://timetracker.anuko.com/user_edit.php.
+'form.user_edit.swap_roles' => 'Alternar funções',
-// Roles form. See example at https://timetracker.anuko.com/roles.php
-// TODO: translate the following.
-// 'form.roles.active_roles' => 'Active Roles',
-// 'form.roles.inactive_roles' => 'Inactive Roles',
-// 'form.roles.rank' => 'Rank',
-// 'form.roles.rights' => 'Rights',
-// 'form.roles.assigned' => 'Assigned',
-// 'form.roles.not_assigned' => 'Not assigned',
-
-// Clients form. See example at https://timetracker.anuko.com/clients.php
+// Roles form. See example at https://timetracker.anuko.com/roles.php.
+'form.roles.active_roles' => 'Funções ativas',
+'form.roles.inactive_roles' => 'Funções inativas',
+'form.roles.rank' => 'Rank',
+'form.roles.rights' => 'Direitos',
+'form.roles.assigned' => 'AtribuÃdo',
+'form.roles.not_assigned' => 'Não atribuÃdo',
+
+// Clients form. See example at https://timetracker.anuko.com/clients.php.
'form.clients.active_clients' => 'Clientes ativos',
'form.clients.inactive_clients' => 'Clientes inativos',
-// Deleting Client form. See example at https://timetracker.anuko.com/client_delete.php
+// Deleting Client form. See example at https://timetracker.anuko.com/client_delete.php.
'form.client.client_to_delete' => 'Cliente a ser apagado',
'form.client.client_entries' => 'Entradas de cliente',
-// Exporting Group Data form. See example at https://timetracker.anuko.com/export.php
-// TODO: replace "team" with "group" in the string below.
-'form.export.hint' => 'Você pode exportar todos os dados da equipe para um arquivo xml. Isto pode ser útil se você estiver migrando os dados para um servidor próprio.',
+// Exporting Group Data form. See example at https://timetracker.anuko.com/export.php.
+'form.export.hint' => 'Você pode exportar todos os dados do grupo para um arquivo xml. Isto pode ser útil se você estiver migrando os dados para um servidor próprio.',
'form.export.compression' => 'Compressão',
'form.export.compression_none' => 'nenhuma',
'form.export.compression_bzip' => 'bzip',
// Importing Group Data form. See example at https://timetracker.anuko.com/import.php (login as admin first).
-'form.import.hint' => 'Importar dados de equipe de um arquivo xml.', // TODO: replace "team" with "group".
+'form.import.hint' => 'Importar dados do grupo de um arquivo xml.',
'form.import.file' => 'Selecionar arquivo',
'form.import.success' => 'Importação realizada com sucesso.',
// Groups form. See example at https://timetracker.anuko.com/admin_groups.php (login as admin first).
-// TODO: replace "team" with "group" in the string below (3 places).
-'form.groups.hint' => 'Crie uma nova equipe fazendo uma nova conta de gerente. Você também pode importar os dados de um arquivo xml de outro servidor Anuko Time Tracker (não havendo colisão de usuários).',
+'form.groups.hint' => 'Crie um novo grupo fazendo uma nova conta de gerente. Você também pode importar os dados de um arquivo xml de outro servidor Anuko Time Tracker (não havendo colisão de usuários).',
// Group Settings form. See example at https://timetracker.anuko.com/group_edit.php.
'form.group_edit.12_hours' => '12 horas',
'form.group_edit.24_hours' => '24 horas',
-// TODO: translate the following.
-// 'form.group_edit.display_options' => 'Display options',
-// 'form.group_edit.holidays' => 'Holidays',
+'form.group_edit.display_options' => 'Opções de exibição',
+'form.group_edit.holidays' => 'Feriados',
'form.group_edit.tracking_mode' => 'Modo de acompanhamento',
'form.group_edit.mode_time' => 'tempo',
'form.group_edit.mode_projects' => 'projetos',
@@ -613,95 +524,84 @@
'form.group_edit.type_all' => 'todos',
'form.group_edit.type_start_finish' => 'inÃcio e fim',
'form.group_edit.type_duration' => 'duração',
+'form.group_edit.punch_mode' => 'Modo punch',
// TODO: translate the following.
-// 'form.group_edit.punch_mode' => 'Punch mode',
-// 'form.group_edit.allow_overlap' => 'Allow overlap',
-// 'form.group_edit.future_entries' => 'Future entries',
-// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
-// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
-// 'form.group_edit.advanced_settings' => 'Advanced settings',
-
-// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
-// TODO: translate the following.
-// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
+'form.group_edit.allow_overlap' => 'Permitir sobreposição',
+'form.group_edit.future_entries' => 'Entradas futuros',
+'form.group_edit.uncompleted_indicators' => 'Indicadores incompletos',
+'form.group_edit.confirm_save' => 'Confirme o salvamento',
+'form.group_edit.advanced_settings' => 'Configurações avançadas',
+
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+'form.group_advanced_edit.allow_ip' => 'Permitir IP',
+// TODO: Translate the following.
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
+// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php.
+'form.group_delete.hint' => 'Tem certeza de que deseja excluir todo o grupo?',
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Para',
'form.mail.report_subject' => 'Relatório do Time Tracker',
-'form.mail.footer' => 'Anuko Time Tracker é um sistema, simples, de fácil uso, de código aberto, de rastreamento do tempo. Visite www.anuko.com para mais informações.',
+'form.mail.footer' => 'Anuko Time Tracker é um sistema de código aberto, de rastreamento do tempo. Visite www.anuko.com para mais informações.',
'form.mail.report_sent' => 'Relatório enviado.',
'form.mail.invoice_sent' => 'Fatura enviada.',
// Quotas configuration form. See example at https://timetracker.anuko.com/quotas.php after enabling Monthly quotas plugin.
-// TODO: translate the following.
-// 'form.quota.year' => 'Year',
-// 'form.quota.month' => 'Month',
-// 'form.quota.workday_hours' => 'Hours in a work day',
-// 'form.quota.hint' => 'If values are empty, quotas are calculated automatically based on workday hours and holidays.',
+'form.quota.year' => 'Ano',
+'form.quota.month' => 'Mês',
+'form.quota.workday_hours' => 'Horas em um dia útil',
+'form.quota.hint' => 'Se os valores estiverem vazios, as cotas serão calculadas automaticamente com base nas horas de trabalho e feriados.',
// Swap roles form. See example at https://timetracker.anuko.com/swap_roles.php.
-// TODO: translate the following.
-// 'form.swap.hint' => 'Demote yourself to a lower role by swapping roles with someone else. This cannot be undone.',
-// 'form.swap.swap_with' => 'Swap roles with',
+'form.swap.hint' => 'Rebaixe-se a função inferior trocando funções com outra pessoa. Isto não pode ser desfeito.',
+'form.swap.swap_with' => 'Trocar função com',
// Work Units configuration form. See example at https://timetracker.anuko.com/work_units.php after enabling Work units plugin.
-// TODO: translate the following.
-// 'form.work_units.minutes_in_unit' => 'Minutes in unit',
-// 'form.work_units.1st_unit_threshold' => '1st unit threshold',
+'form.work_units.minutes_in_unit' => 'Minutos em unidade',
+'form.work_units.1st_unit_threshold' => 'Limiar da 1ª unidade',
// Roles and rights. These strings are used in multiple places. Grouped here to provide consistent translations.
-// TODO: translate the following.
-// 'role.user.label' => 'User',
-// 'role.user.low_case_label' => 'user',
-// 'role.user.description' => 'A regular member without management rights.',
-// 'role.client.label' => 'Client',
-// 'role.client.low_case_label' => 'client',
-// 'role.client.description' => 'A client can view its own data.',
-// 'role.supervisor.label' => 'Supervisor',
-// 'role.supervisor.low_case_label' => 'supervisor',
-// 'role.supervisor.description' => 'A person with a small set of management rights.',
-// 'role.comanager.label' => 'Co-manager',
-// 'role.comanager.low_case_label' => 'co-manager',
-// 'role.comanager.description' => 'A person with a big set of management functions.',
-// 'role.manager.label' => 'Manager',
-// 'role.manager.low_case_label' => 'manager',
-// 'role.manager.description' => 'Group manager. Can do most of things for a group.',
-// 'role.top_manager.label' => 'Top manager',
-// 'role.top_manager.low_case_label' => 'top manager',
-// 'role.top_manager.description' => 'Top group manager. Can do everything in a tree of groups.',
-// 'role.admin.label' => 'Administrator',
-// 'role.admin.low_case_label' => 'administrator',
-// 'role.admin.description' => 'Site adminsitrator.',
+'role.user.label' => 'Usuário',
+'role.user.low_case_label' => 'usuário',
+'role.user.description' => 'Um membro regular sem direitos de gestão.',
+'role.client.label' => 'Cliente',
+'role.client.low_case_label' => 'cliente',
+'role.client.description' => 'Um cliente pode visualizar seus próprios dados.',
+'role.supervisor.label' => 'Supervisor',
+'role.supervisor.low_case_label' => 'supervisor',
+'role.supervisor.description' => 'Uma pessoa com um pequeno conjunto de direitos de gerenciamento.',
+'role.comanager.label' => 'Co-gerente',
+'role.comanager.low_case_label' => 'co-gerente',
+'role.comanager.description' => 'Uma pessoa com um grande conjunto de funções de gerenciamento.',
+'role.manager.label' => 'Gerente',
+'role.manager.low_case_label' => 'gerente',
+'role.manager.description' => 'Gerente de grupo. Pode fazer a maioria das coisas para um grupo.',
+'role.top_manager.label' => 'Gerente geral',
+'role.top_manager.low_case_label' => 'gerente geral',
+'role.top_manager.description' => 'Principal gerente de grupo. Pode fazer tudo em uma árvore de grupos.',
+'role.admin.label' => 'Administrador',
+'role.admin.low_case_label' => 'administrador',
+'role.admin.description' => 'Adminsitrador do site/sistema.',
// Timesheet View form. See example at https://timetracker.anuko.com/timesheet_view.php.
-// TODO: translate the following.
-// 'form.timesheet_view.submit_subject' => 'Timesheet approval request',
-// 'form.timesheet_view.submit_body' => "A new timesheet requires approval. User: %s.",
-// 'form.timesheet_view.approve_subject' => 'Timesheet approved',
-// 'form.timesheet_view.approve_body' => "Your timesheet %s was approved. %s",
-// 'form.timesheet_view.disapprove_subject' => 'Timesheet not approved',
-// 'form.timesheet_view.disapprove_body' => "Your timesheet %s was not approved. %s",
+'form.timesheet_view.submit_subject' => 'Solicitação de aprovação de planilha de horas',
+'form.timesheet_view.submit_body' => "Uma nova planilha de horas requer aprovação. Usuário: %s.",
+'form.timesheet_view.approve_subject' => 'Planilha de horas aprovada',
+'form.timesheet_view.approve_body' => "Sua planilha de horas %s foi aprovada. %s",
+'form.timesheet_view.disapprove_subject' => 'Planilha de horas não aprovada',
+'form.timesheet_view.disapprove_body' => "Sua planilha de horas %s não foi aprovada. %s",
// Display Options form. See example at https://timetracker.anuko.com/display_options.php.
+'form.display_options.note_on_separate_row' => 'Anotação em linha separada',
+'form.display_options.not_complete_days' => 'Dias não completos',
// TODO: translate the following.
-// 'form.display_options.note_on_separate_row' => 'Note on separate row',
-// 'form.display_options.not_complete_days' => 'Not complete days',
-// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
+'form.display_options.custom_css' => 'CSS customizado',
// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
+
diff --git a/WEB-INF/resources/pt.lang.php b/WEB-INF/resources/pt.lang.php
index b4aa0cc02..abcd5793f 100644
--- a/WEB-INF/resources/pt.lang.php
+++ b/WEB-INF/resources/pt.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Tempo',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Relatórios',
@@ -65,7 +43,6 @@
'menu.users' => 'Usuários',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
// 'menu.export' => 'Export',
// 'menu.clients' => 'Clients',
'menu.options' => 'Opções',
@@ -96,6 +73,8 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
// 'error.auth' => 'Incorrect login or password.',
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
// 'error.user_exists' => 'User with this login already exists.',
// 'error.object_exists' => 'Object with this name already exists.',
// 'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -118,7 +97,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -149,9 +127,11 @@
// 'button.export' => 'Export group',
// 'button.import' => 'Import group',
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -213,6 +193,7 @@
// 'label.select_none' => 'Deselect all',
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
// 'label.id' => 'ID',
// 'label.language' => 'Language',
// 'label.decimal_mark' => 'Decimal mark',
@@ -234,10 +215,6 @@
'label.required_fields' => '* campos obrigatórios',
// TODO: translate the following.
// 'label.on_behalf' => 'on behalf of',
-'label.role_manager' => '(gerente)',
-// TODO: translate the following.
-// 'label.role_comanager' => '(co-manager)',
-// 'label.role_admin' => '(administrator)',
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
// 'label.yes' => 'yes',
@@ -260,9 +237,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
// 'label.totals_only' => 'Totals only',
@@ -278,20 +255,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -305,9 +270,9 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'Login',
-// TODO: translate the following.
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
// 'title.groups' => 'Groups',
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
// 'title.delete_group' => 'Deleting Group',
@@ -317,6 +282,7 @@
// 'title.edit_time_record' => 'Editing Time Record',
// 'title.delete_time_record' => 'Deleting Time Record',
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -400,22 +366,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -447,7 +397,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -458,13 +407,23 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Esqueceu a senha?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
// TODO: translate the following.
// 'form.reset_password.message' => 'Password reset request sent by email.',
// 'form.reset_password.email_subject' => 'Anuko Time Tracker password reset request',
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -501,10 +460,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Selecione o perÃodo de tempo',
'form.reports.set_period' => 'ou selecionar datas',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Exibir campos',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
// 'form.reports.group_by' => 'Group by',
// 'form.reports.group_by_no' => '--- no grouping ---',
// 'form.reports.group_by_date' => 'date',
@@ -517,6 +479,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
// TODO: translate the following.
// 'form.report.export' => 'Export',
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -530,8 +493,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
// TODO: translate the following.
// 'form.invoice.number' => 'Invoice number',
// 'form.invoice.person' => 'Person',
@@ -558,6 +521,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
// 'form.users.role' => 'Role',
'form.users.manager' => 'Gerente',
@@ -621,13 +585,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -636,7 +606,7 @@
'form.mail.to' => 'Para',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
// 'form.mail.invoice_sent' => 'Invoice sent.',
@@ -694,21 +664,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/ro.lang.php b/WEB-INF/resources/ro.lang.php
index 419b26467..03db7da44 100644
--- a/WEB-INF/resources/ro.lang.php
+++ b/WEB-INF/resources/ro.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Timpul',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Rapoarte',
@@ -65,7 +43,6 @@
'menu.users' => 'Utilizatori',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
// 'menu.export' => 'Export',
'menu.clients' => 'Clienti',
// TODO: translate the following.
@@ -102,6 +79,8 @@
// 'error.record' => 'Select record.',
'error.auth' => 'Nume de utilizator sau parola incorecta.',
// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
// 'error.user_exists' => 'User with this login already exists.',
// 'error.object_exists' => 'Object with this name already exists.',
// 'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -125,7 +104,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -156,9 +134,11 @@
'button.import' => 'Importa echipa', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -223,6 +203,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
// TODO: translate the following.
// 'label.language' => 'Language',
@@ -244,9 +225,6 @@
// 'label.ldap_hint' => 'Type your Windows login and password in the fields below.',
'label.required_fields' => '* date obligatorii',
'label.on_behalf' => 'in numele',
-'label.role_manager' => '(manager)',
-'label.role_comanager' => '(co-manager)',
-'label.role_admin' => '(administrator)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -271,9 +249,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Numai totaluri',
@@ -290,20 +268,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -320,9 +286,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'Autentificare',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Echipe', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'Șterge echipa', // TODO: change "team" to "group".
@@ -334,6 +301,7 @@
'title.delete_time_record' => 'Ștergerea inregistrarii timpului',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -418,22 +386,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.add_offer' => 'Adding Offer',
-// 'title.offer' => 'Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -467,7 +419,6 @@
// TODO: translate the following.
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -478,15 +429,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Parola pierduta?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Cererea de resetare a parolei a fost trimisa.', // TODO: add "by email" to match the English string.
'form.reset_password.email_subject' => 'Anuko Time Tracker - cerere de resetare a parolei',
-// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Draga Utilizator,\n\nCineva, IP %s, a cerut resetarea parolei pentru contul Anuko Time Tracker. Te rog, viziteaza acesta legatura daca doresti sa iti resetezi parola.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+'form.reset_password.email_body' => "Draga Utilizator,\n\nCineva, IP %s, a cerut resetarea parolei pentru contul Anuko Time Tracker. Te rog, viziteaza acesta legatura daca doresti sa iti resetezi parola.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -522,10 +483,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Alege perioada',
'form.reports.set_period' => 'sau introdu intervalul de date',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Arata campuri',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Grupat dupa',
'form.reports.group_by_no' => '--- fara grupare ---',
'form.reports.group_by_date' => 'data',
@@ -539,6 +503,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exporta',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -552,8 +517,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Numar factura',
'form.invoice.person' => 'Persoana',
@@ -579,6 +544,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Functie', // TODO: is "Rol" a better term here?
'form.users.manager' => 'Manager',
@@ -642,13 +608,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -657,7 +629,7 @@
'form.mail.to' => 'Catre',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'Factura trimisa.',
@@ -715,21 +687,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/ru.lang.php b/WEB-INF/resources/ru.lang.php
index 49ee3edeb..6c924df2d 100644
--- a/WEB-INF/resources/ru.lang.php
+++ b/WEB-INF/resources/ru.lang.php
@@ -1,32 +1,9 @@
'Группа',
'menu.plugins' => 'Плагины',
'menu.time' => 'ВремÑ',
+'menu.puncher' => 'Пробить',
'menu.week' => 'ÐеделÑ',
'menu.expenses' => 'РаÑходы',
'menu.reports' => 'Отчёты',
@@ -56,7 +34,6 @@
'menu.tasks' => 'Задачи',
'menu.users' => 'Пользователи',
'menu.groups' => 'Группы',
-'menu.subgroups' => 'Подгруппы',
'menu.export' => 'ÐкÑпорт',
'menu.clients' => 'Клиенты',
'menu.options' => 'Опции',
@@ -83,6 +60,8 @@
'error.report' => 'Выберите отчёт.',
'error.record' => 'Выберите запиÑÑŒ.',
'error.auth' => 'Ðеправильно введен логин или пароль.',
+'error.2fa_code' => 'Ðеверный код 2FA.',
+'error.weak_password' => 'Слабый пароль.',
'error.user_exists' => 'Пользователь Ñ Ñ‚Ð°ÐºÐ¸Ð¼ логином уже ÑущеÑтвует.',
'error.object_exists' => 'Объект Ñ Ñ‚Ð°ÐºÐ¸Ð¼ именем уже еÑть.',
'error.invoice_exists' => 'Счёт Ñ Ñ‚Ð°ÐºÐ¸Ð¼ номером уже еÑть.',
@@ -105,7 +84,6 @@
'error.user_count' => 'Ограничение на количеÑтво пользователей.',
'error.expired' => 'ДоÑтигнута дата ÑкÑпирации.',
'error.file_storage' => 'Ошибка Ñервера Ð´Ð»Ñ Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð².',
-'error.remote_work' => 'Ошибка Ñервера удаленной работы.',
// Warning messages.
'warn.sure' => 'Вы уверены?',
@@ -131,9 +109,11 @@
'button.export' => 'ÐкÑпортировать группу',
'button.import' => 'Импортировать группу',
'button.close' => 'Закрыть',
+'button.start' => 'Ðачать',
'button.stop' => 'Завершить',
'button.approve' => 'Одобрить',
'button.disapprove' => 'Ðе одобрить',
+'button.sync' => 'Синхронизовать',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.menu' => 'Меню',
@@ -188,6 +168,7 @@
'label.select_none' => 'СнÑть вÑе отметки',
'label.day_view' => 'День',
'label.week_view' => 'ÐеделÑ',
+'label.puncher' => 'Пробиватель',
'label.id' => 'ID',
'label.language' => 'Язык',
'label.decimal_mark' => 'ДеÑÑтичный знак',
@@ -206,9 +187,6 @@
'label.ldap_hint' => 'Введите Ñвои Windows логин и пароль в Ð¿Ð¾Ð»Ñ Ð½Ð¸Ð¶Ðµ.',
'label.required_fields' => '* - обÑзательные Ð´Ð»Ñ Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð»Ñ',
'label.on_behalf' => 'от имени',
-'label.role_manager' => '(менеджер)',
-'label.role_comanager' => '(аÑÑиÑтент менеджера)',
-'label.role_admin' => '(админиÑтратор)',
'label.page' => 'Стр',
'label.condition' => 'УÑловие',
'label.yes' => 'да',
@@ -230,9 +208,9 @@
'label.paid_status' => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¾Ð¿Ð»Ð°Ñ‚Ñ‹',
'label.paid' => 'Оплачено',
'label.mark_paid' => 'Отметить оплату',
-'label.week_menu' => 'Меню недели',
'label.week_note' => 'Комментарий недели',
'label.week_list' => 'СпиÑок недели',
+'label.weekends' => 'Выходные',
'label.work_units' => 'Единицы работы',
'label.work_units_short' => 'Единицы',
'label.totals_only' => 'Только итоги',
@@ -248,17 +226,8 @@
'label.attachments' => 'ПриложениÑ',
'label.files' => 'Файлы',
'label.file' => 'Файл',
-'label.image' => 'Изображение',
-'label.download' => 'Скачать',
'label.active_users' => 'Ðктивные пользователи',
'label.inactive_users' => 'Ðеактивные пользователи',
-'label.details' => 'Детали',
-'label.budget' => 'Бюджет',
-'label.work' => 'Работа',
-'label.offer' => 'Предложение',
-'label.contractor' => 'ПодрÑдчик',
-'label.how_to_pay' => 'Как оплатить',
-'label.moderator_comment' => 'Комментарий модератора',
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -270,8 +239,8 @@
'title.error' => 'Ошибка',
'title.success' => 'УÑпех',
'title.login' => 'Вход в ÑиÑтему',
+'title.2fa' => 'Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ',
'title.groups' => 'Группы',
-'title.subgroups' => 'Подгруппы',
'title.add_group' => 'Добавление группы',
'title.edit_group' => 'Редактирование группы',
'title.delete_group' => 'Удаление группы',
@@ -281,6 +250,7 @@
'title.edit_time_record' => 'Редактирование запиÑи о времени',
'title.delete_time_record' => 'Удаление запиÑи о времени',
'title.time_files' => 'Файлы запиÑи о времени',
+'title.puncher' => 'Пробиватель',
'title.expenses' => 'РаÑходы',
'title.edit_expense' => 'Редактирование предмета раÑхода',
'title.delete_expense' => 'Удаление предмета раÑхода',
@@ -356,22 +326,6 @@
'title.edit_file' => 'Редактирование файла',
'title.delete_file' => 'Удаление файла',
'title.download_file' => 'Скачивание файла',
-'title.work' => 'Работа',
-'title.add_work' => 'Добавление работы',
-'title.edit_work' => 'Редактирование работы',
-'title.delete_work' => 'Удаление работы',
-'title.active_work' => 'ÐÐºÑ‚Ð¸Ð²Ð½Ð°Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð°',
-'title.available_work' => 'ИмеющаÑÑÑ Ñ€Ð°Ð±Ð¾Ñ‚Ð°',
-'title.inactive_work' => 'ÐÐµÐ°ÐºÑ‚Ð¸Ð²Ð½Ð°Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð°',
-'title.pending_work' => 'Работа в ожидании',
-'title.offer' => 'Предложение',
-'title.add_offer' => 'Добавление предложениÑ',
-'title.edit_offer' => 'Редактирование предложениÑ',
-'title.delete_offer' => 'Удаление предложениÑ',
-'title.active_offers' => 'Ðктивные предложениÑ',
-'title.available_offers' => 'ИмеющиеÑÑ Ð¿Ñ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ',
-'title.inactive_offers' => 'Ðеактивные предложениÑ',
-'title.pending_offers' => 'ÐŸÑ€ÐµÐ´Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð² ожидании',
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -400,7 +354,6 @@
'dropdown.status_inactive' => 'неактивный',
'dropdown.delete' => 'удалить',
'dropdown.do_not_delete' => 'не удалÑть',
-'dropdown.pending_approval' => 'в ожидании одобрениÑ',
'dropdown.approved' => 'одобрено',
'dropdown.not_approved' => 'не одобрено',
'dropdown.paid' => 'оплачено',
@@ -415,12 +368,20 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Забыли пароль?',
-'form.login.about' => 'Anuko Time Tracker - Ñто Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°Ñ (open source), проÑÑ‚Ð°Ñ Ð¸ Ð»Ñ‘Ð³ÐºÐ°Ñ Ð² иÑпользовании ÑиÑтема трекинга рабочего времени.',
+'form.login.about' => 'Anuko Time Tracker - Ñто Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°Ñ (open source) ÑиÑтема трекинга рабочего времени.',
+
+// Email subject and body for two-factor authentication.
+'email.2fa_code.subject' => 'Anuko Time Tracker код Ð´Ð»Ñ Ð´Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð¾Ð¹ аутентификации',
+'email.2fa_code.body' => "Уважаемый пользователь,\n\nВаш код Ð´Ð»Ñ Ð´Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð¾Ð¹ аутентификации:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+'form.2fa.hint' => 'Проверьте Ñлектронную почту и введите выÑланный вам 2FA код здеÑÑŒ.',
+'form.2fa.2fa_code' => '2FA код',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Ð—Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° ÑÐ±Ñ€Ð¾Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð¾Ñ‚Ð¾Ñлан по e-mail.',
'form.reset_password.email_subject' => 'Ð¡Ð±Ñ€Ð¾Ñ Ð¿Ð°Ñ€Ð¾Ð»Ñ Ðº Anuko Time Tracker',
-'form.reset_password.email_body' => "Уважаемый пользователь,\n\nКто-то c IP %s попроÑил ÑброÑить ваш пароль к ÑиÑтеме Anuko Time Tracker. Пройдите по данной ÑÑылке Ð´Ð»Ñ ÑброÑа паролÑ.\n\n%s\n\nAnuko Time Tracker - Ñто Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°Ñ (open source), проÑÑ‚Ð°Ñ Ð¸ Ð»Ñ‘Ð³ÐºÐ°Ñ Ð² иÑпользовании ÑиÑтема трекинга рабочего времени. ПодробноÑти - на Ñайте https://www.anuko.com.",
+'form.reset_password.email_body' => "Уважаемый пользователь,\n\nКто-то c IP %s попроÑил ÑброÑить ваш пароль к ÑиÑтеме Anuko Time Tracker. Пройдите по данной ÑÑылке Ð´Ð»Ñ ÑброÑа паролÑ.\n\n%s\n\nAnuko Time Tracker - Ñто Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°Ñ (open source) ÑиÑтема трекинга рабочего времени. ПодробноÑти - на Ñайте https://www.anuko.com.",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Впечатайте новый пароль и нажмите Cохранить.',
@@ -452,9 +413,11 @@
'form.reports.include_pending' => 'в ожидании',
'form.reports.select_period' => 'Выберите интервал времени',
'form.reports.set_period' => 'или укажите даты',
+'form.reports.note_containing' => 'Комментарий Ñодержит',
'form.reports.show_fields' => 'Показывать полÑ',
-'form.reports.time_fields' => 'Time fields',
-'form.reports.user_fields' => 'ÐŸÐ¾Ð»Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸',
+'form.reports.time_fields' => 'ÐŸÐ¾Ð»Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸',
+'form.reports.user_fields' => 'ÐŸÐ¾Ð»Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ',
+'form.reports.project_fields' => 'ÐŸÐ¾Ð»Ñ Ð¿Ñ€Ð¾ÐµÐºÑ‚Ð°',
'form.reports.group_by' => 'Группировать по',
'form.reports.group_by_no' => '--- без группировки ---',
'form.reports.group_by_date' => 'дате',
@@ -466,6 +429,7 @@
// Report form. See example at https://timetracker.anuko.com/report.php
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'ÐкÑпортировать',
+'form.report.per_hour' => 'За чаÑ',
'form.report.assign_to_invoice' => 'Включить в Ñчёт',
'form.report.assign_to_timesheet' => 'Включить в табель',
@@ -477,8 +441,8 @@
'form.templates.active_templates' => 'Ðктивные шаблоны',
'form.templates.inactive_templates' => 'Ðеактивные шаблоны',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Ðомер Ñчёта',
'form.invoice.person' => 'Работник',
@@ -500,6 +464,7 @@
'form.tasks.inactive_tasks' => 'Ðеактивные задачи',
// Users form. See example at https://timetracker.anuko.com/users.php
+'form.users.uncompleted_entry_today' => 'Пользователь имеет неоконченную запиÑÑŒ ÑегоднÑ',
'form.users.uncompleted_entry' => 'Пользователь имеет неоконченную запиÑÑŒ',
'form.users.role' => 'Роль',
'form.users.manager' => 'Менеджер',
@@ -554,20 +519,25 @@
'form.group_edit.type_start_finish' => 'начало и конец',
'form.group_edit.type_duration' => 'длительноÑть',
'form.group_edit.punch_mode' => 'Пробивать времÑ',
+'form.group_edit.one_uncompleted' => 'Одна незавершённаÑ',
'form.group_edit.allow_overlap' => 'Возможное перекрывание',
'form.group_edit.future_entries' => 'Будущие запиÑи',
'form.group_edit.uncompleted_indicators' => 'Индикаторы незавершениÑ',
'form.group_edit.confirm_save' => 'Предупреждать при Ñохранении',
-'form.group_edit.allow_ip' => 'Разрешить доÑтуп Ñ IP',
'form.group_edit.advanced_settings' => 'Продвинутые наÑтройки',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+'form.group_advanced_edit.allow_ip' => 'Разрешить доÑтуп Ñ IP',
+'form.group_advanced_edit.password_complexity' => 'СложноÑть паролÑ',
+'form.group_advanced_edit.2fa' => 'Ð”Ð²ÑƒÑ…Ñ„Ð°ÐºÑ‚Ð¾Ñ€Ð½Ð°Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
'form.group_delete.hint' => 'Ð’Ñ‹ уверены, что хотите удалить вÑÑŽ группу?',
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Кому',
'form.mail.report_subject' => 'Time Tracker отчёт',
-'form.mail.footer' => 'Anuko Time Tracker - Ñто Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°Ñ (open source), проÑÑ‚Ð°Ñ Ð¸ Ð»Ñ‘Ð³ÐºÐ°Ñ Ð² иÑпользовании ÑиÑтема трекинга рабочего времени. ПодробноÑти на Ñайте www.anuko.com.',
+'form.mail.footer' => 'Anuko Time Tracker - Ñто Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð°Ñ (open source) ÑиÑтема трекинга рабочего времени. ПодробноÑти на Ñайте www.anuko.com.',
'form.mail.report_sent' => 'Отчёт отправлен.',
'form.mail.invoice_sent' => 'Счёт отправлен.',
@@ -619,20 +589,8 @@
// Display Options form. See example at https://timetracker.anuko.com/display_options.php.
'form.display_options.note_on_separate_row' => 'Комментарий в отдельном Ñ€Ñду',
'form.display_options.not_complete_days' => 'Ðезавершенные дни',
+'form.display_options.inactive_projects' => 'Ðеактивные проекты',
+'form.display_options.cost_per_hour' => 'СтоимоÑть за чаÑ',
'form.display_options.custom_css' => 'ПользовательÑÐºÐ°Ñ CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-'work.error.work_not_available' => 'Работа отÑутÑтвует.',
-'work.error.offer_not_available' => 'Предложение отÑутÑтвует.',
-'work.type.one_time' => 'одноразоваÑ',
-'work.type.ongoing' => 'поÑтоÑннаÑ',
-'work.label.own_work' => 'Ð¡Ð²Ð¾Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ð°',
-'work.label.own_offers' => 'Свои предложениÑ',
-'work.label.offers' => 'ПредложениÑ',
-'work.button.send_message' => 'Отправить Ñообщение',
-'work.button.make_offer' => 'Сделать предложение',
-'work.button.accept' => 'ПринÑть',
-'work.button.decline' => 'Отклонить',
-'work.title.send_message' => 'ОтÑылка ÑообщениÑ',
-'work.msg.message_sent' => 'Сообщение отоÑлано.',
+'form.display_options.custom_translation' => 'ПользовательÑкий перевод',
);
diff --git a/WEB-INF/resources/sk.lang.php b/WEB-INF/resources/sk.lang.php
index eceb1e521..0404fb8d0 100644
--- a/WEB-INF/resources/sk.lang.php
+++ b/WEB-INF/resources/sk.lang.php
@@ -1,32 +1,9 @@
'Moduly',
'menu.time' => 'Časový záznam',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Zostavy',
@@ -61,7 +39,6 @@
'menu.users' => 'PoužÃvatelia',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Export',
'menu.clients' => 'Klienti',
'menu.options' => 'Nastavenia',
@@ -94,6 +71,9 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
'error.auth' => 'Nesprávne prihlasovacie meno alebo heslo.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'PoužÃvateľ s týmto prihlasovacÃm menom už existuje.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -123,7 +103,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -153,9 +132,11 @@
'button.import' => 'ImportovaÅ¥ tÃm', // TODO: replace "team" with "group".
'button.close' => 'Zatvoriť',
// TODO: translate the following.
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -217,6 +198,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Jazyk',
// TODO: translate the following.
@@ -236,9 +218,6 @@
'label.ldap_hint' => 'Zadajte prihlasovacie meno do Windowsu a heslo do polà nižšie.',
'label.required_fields' => '* - povinné polia',
'label.on_behalf' => 'v zastúpenÃ',
-'label.role_manager' => '(manažér)',
-'label.role_comanager' => '(spolu-manažér)',
-'label.role_admin' => '(administrátor)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -264,9 +243,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Iba celkové',
@@ -283,21 +262,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'AktÃvny použÃvatelia',
'label.inactive_users' => 'NeaktÃvny použÃvatelia',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -311,9 +277,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'Prihlásenie',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'TÃmy', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'Vymazávanie tÃmu', // TODO: change "team" to "group".
@@ -324,6 +291,7 @@
'title.delete_time_record' => 'Vymazávanie Äasového záznamu',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -403,22 +371,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -452,7 +404,6 @@
// TODO: translate the following.
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -467,15 +418,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Zabudnuté heslo?',
-'form.login.about' => 'Anuko Time Tracker je jednoduchý a ľahko použiteľný systém na sledovanie Äasu s otvoreným zdrojovým kódom.',
+'form.login.about' => 'Anuko Time Tracker je systém na sledovanie Äasu s otvoreným zdrojovým kódom.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Žiadosť o obnovenie hesla bola odoslaná e-mailom.',
'form.reset_password.email_subject' => 'Žiadosť o obnovenie hesla do Anuko Time Tracker',
// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Vážený použÃvateľ,\n\nniekto, IP %s, si vyžiadal obnovenie vášho hesla do Anuko Time Tracker. ProsÃm kliknite na nasledujúcu linku, ak si prajete obnoviÅ¥ heslo.\n\n%s\n\nAnuko Time Tracker je jednoduchý a ľahko použiteľný systém na sledovanie Äasu s otvoreným zdrojovým kódom. NavÅ¡tÃvte https://www.anuko.com pre viac informáciÃ.\n\n",
+'form.reset_password.email_body' => "Vážený použÃvateľ,\n\nniekto, IP %s, si vyžiadal obnovenie vášho hesla do Anuko Time Tracker. ProsÃm kliknite na nasledujúcu linku, ak si prajete obnoviÅ¥ heslo.\n\n%s\n\nAnuko Time Tracker je systém na sledovanie Äasu s otvoreným zdrojovým kódom. NavÅ¡tÃvte https://www.anuko.com pre viac informáciÃ.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
'form.change_password.tip' => 'Zadajte nové heslo a kliknite na Uložiť.',
@@ -510,10 +471,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Vyberte Äasový rozsah',
'form.reports.set_period' => 'alebo nastavte dátumy',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Zobraziť polia',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
// 'form.reports.group_by' => 'Group by',
// 'form.reports.group_by_no' => '--- no grouping ---',
'form.reports.group_by_date' => 'dátum',
@@ -526,6 +490,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exportovať',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -539,8 +504,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'ÄŒÃslo faktúry',
'form.invoice.person' => 'Osoba',
@@ -564,6 +529,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Rola',
'form.users.manager' => 'Manažér',
@@ -625,13 +591,19 @@
'form.group_edit.type_duration' => 'trvanie',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -639,7 +611,7 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Komu',
'form.mail.report_subject' => 'Time Tracker zostava',
-'form.mail.footer' => 'Anuko Time Tracker je jednoduchý a ľahko použiteľný systém na sledovanie Äasu s otvoreným zdrojovým kódom. NavÅ¡tÃvte www.anuko.com pre viac informáciÃ.',
+'form.mail.footer' => 'Anuko Time Tracker je systém na sledovanie Äasu s otvoreným zdrojovým kódom. NavÅ¡tÃvte www.anuko.com pre viac informáciÃ.',
'form.mail.report_sent' => 'Zostava odoslaná.',
'form.mail.invoice_sent' => 'Faktúra odoslaná.',
@@ -697,21 +669,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/sl.lang.php b/WEB-INF/resources/sl.lang.php
index 8ee642e54..b3153ad79 100644
--- a/WEB-INF/resources/sl.lang.php
+++ b/WEB-INF/resources/sl.lang.php
@@ -1,32 +1,9 @@
'Group',
// 'menu.plugins' => 'Plugins',
// 'menu.time' => 'Time',
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'PoroÄila',
@@ -63,7 +41,6 @@
// 'menu.tasks' => 'Tasks',
// 'menu.users' => 'Users',
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
// 'menu.export' => 'Export',
'menu.clients' => 'Stranke',
'menu.options' => 'Možnosti',
@@ -93,6 +70,8 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
// 'error.auth' => 'Incorrect login or password.',
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
// 'error.user_exists' => 'User with this login already exists.',
// 'error.object_exists' => 'Object with this name already exists.',
// 'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -115,7 +94,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -146,9 +124,11 @@
'button.import' => 'Uvozi tim', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -210,6 +190,7 @@
// 'label.select_none' => 'Deselect all',
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
// 'label.id' => 'ID',
// 'label.language' => 'Language',
// 'label.decimal_mark' => 'Decimal mark',
@@ -230,9 +211,6 @@
// 'label.ldap_hint' => 'Type your Windows login and password in the fields below.',
// 'label.required_fields' => '* - required fields',
// 'label.on_behalf' => 'on behalf of',
-// 'label.role_manager' => '(manager)',
-// 'label.role_comanager' => '(co-manager)',
-// 'label.role_admin' => '(administrator)',
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
// 'label.yes' => 'yes',
@@ -255,9 +233,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
// 'label.totals_only' => 'Totals only',
@@ -273,20 +251,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -300,9 +266,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'Prijava',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Timi', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
// 'title.delete_group' => 'Deleting Group',
@@ -313,6 +280,7 @@
// 'title.edit_time_record' => 'Editing Time Record',
// 'title.delete_time_record' => 'Deleting Time Record',
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -393,22 +361,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -439,7 +391,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -450,16 +401,26 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
// TODO: translate the following.
// 'form.login.forgot_password' => 'Forgot password?',
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Zahteva za razveljavitev gesla je bila poslana.', // TODO: add "by email" to match the English string.
'form.reset_password.email_subject' => 'Anuko Time Tracker zahteva za razveljavitev gesla',
// TODO: translate the ending of this string properly.
-// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. "from IP" added. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "SpoÅ¡tovani uporabnik,\n\nNekdo, IP %s, je zahteval razveljavitev vaÅ¡ega Anuko Time Tracker gesla. Prosimo obiÅ¡Äite to povezavo, Äe želite razveljaviti vaÅ¡e geslo.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+'form.reset_password.email_body' => "SpoÅ¡tovani uporabnik,\n\nNekdo, IP %s, je zahteval razveljavitev vaÅ¡ega Anuko Time Tracker gesla. Prosimo obiÅ¡Äite to povezavo, Äe želite razveljaviti vaÅ¡e geslo.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -496,9 +457,11 @@
// 'form.reports.include_pending' => 'pending',
// 'form.reports.select_period' => 'Select time period',
// 'form.reports.set_period' => 'or set dates',
+// 'form.reports.note_containing' => 'Note containing',
// 'form.reports.show_fields' => 'Show fields',
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
// 'form.reports.group_by' => 'Group by',
// 'form.reports.group_by_no' => '--- no grouping ---',
// 'form.reports.group_by_date' => 'date',
@@ -512,6 +475,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
// TODO: translate the following.
// 'form.report.export' => 'Export',
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -525,8 +489,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
// TODO: translate the following.
// 'form.invoice.number' => 'Invoice number',
// 'form.invoice.person' => 'Person',
@@ -553,6 +517,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
// 'form.users.role' => 'Role',
// 'form.users.manager' => 'Manager',
@@ -615,13 +580,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -630,7 +601,7 @@
'form.mail.to' => 'Za',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
// 'form.mail.invoice_sent' => 'Invoice sent.',
@@ -688,21 +659,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/sr.lang.php b/WEB-INF/resources/sr.lang.php
index 8bc2e7223..6902d9223 100644
--- a/WEB-INF/resources/sr.lang.php
+++ b/WEB-INF/resources/sr.lang.php
@@ -1,32 +1,9 @@
'Dodaci',
'menu.time' => 'Vreme',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Troškovi',
'menu.reports' => 'Izveštaji',
@@ -61,7 +39,6 @@
'menu.users' => 'Korisnici',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Izvoz',
'menu.clients' => 'Klijenti',
'menu.options' => 'Opcije',
@@ -90,6 +67,9 @@
// TODO: translate the following.
// 'error.record' => 'Select record.',
'error.auth' => 'PogreÅ¡no korisniÄko ime ili lozinka.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Korisnik pod ovim imenom već postoji.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -119,7 +99,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -147,10 +126,13 @@
'button.export' => 'Izvezi tim', // TODO: replace "team" with "group".
'button.import' => 'Uvezi tim', // TODO: replace "team" with "group".
'button.close' => 'Zatvori',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'Stani',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -212,6 +194,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Jezik',
'label.decimal_mark' => 'Decimala',
@@ -230,9 +213,6 @@
'label.ldap_hint' => 'Unesi tvoju Windows prijavu i lozinku u polje ispod.',
'label.required_fields' => '* - obavezna polja',
'label.on_behalf' => 'ispred',
-'label.role_manager' => '(menadžer)',
-'label.role_comanager' => '(saradnik)',
-'label.role_admin' => '(administrator)',
'label.page' => 'Strana',
// TODO: translate the following.
// 'label.condition' => 'Condition',
@@ -259,9 +239,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
'label.totals_only' => 'Samo zbirno',
// TODO: translate the following.
@@ -277,21 +257,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'Aktivni korisnik',
'label.inactive_users' => 'Neaktivni korisnik',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -305,9 +272,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'Prijava',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Timovi', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
'title.edit_group' => 'Izmeni tim', // TODO: change "team" to "group".
'title.delete_group' => 'Obriši tim', // TODO: change "team" to "group".
@@ -318,6 +286,7 @@
'title.delete_time_record' => 'Obriši unos vremena',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Troškovi',
'title.edit_expense' => 'Izmeni stavke troškova',
'title.delete_expense' => 'Obriši stavke troškova',
@@ -398,22 +367,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -446,7 +399,6 @@
'dropdown.delete' => 'obriši',
'dropdown.do_not_delete' => 'nemoj obrisati',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -461,13 +413,25 @@
// Forma prijave. Pogledajte primer na https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Zaboravili ste lozinku?',
+ // TODO: re-translate form.login.about as it has changed.
+ // 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
'form.login.about' => 'Anuko Time Tracker je jednostavan i lak za korišćenje za praćenje radnog vremena.',
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
+
// Izmena forme za lozinku. Pogledajte primer na https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Zahtev za izmenu lozinke je poslat mejlom.',
'form.reset_password.email_subject' => 'Anuko Time Tracker zahtev za izmenu lozinke',
-// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
'form.reset_password.email_body' => "PoÅ¡tovani korisniÄe,\n\nneko, IP %s, ste poslali zahtev za izmenu lozinke na Anuko Time Tracker nalogu. Molimo da pratite link ako želite da izmenite lozinku.\n\n%s\n\nAnuko Time Tracker je jednostavan i lak za korišćenje za praćenje radnog vremena. Posetite nas na https://www.anuko.com za viÅ¡e informacija.\n\n",
@@ -504,10 +468,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Odaberi vremenski raspon',
'form.reports.set_period' => 'ili podesi datum',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Prikaži polja u izveštaju',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Grupiši po',
'form.reports.group_by_no' => '--- nemoj grupisati ---',
'form.reports.group_by_date' => 'datum',
@@ -520,6 +487,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Izvoz',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -533,8 +501,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Forma izveštaja. Pogledajte primer na https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Broj raÄuna',
'form.invoice.person' => 'Osoba',
@@ -558,6 +526,7 @@
// KorisniÄka forma. Pogledajte primer na https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Funkcija',
'form.users.manager' => 'Menadžer',
@@ -618,13 +587,19 @@
'form.group_edit.type_duration' => 'trajanje',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -632,6 +607,8 @@
// Forma mejla. Pogledajte primer na https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Za',
'form.mail.report_subject' => 'Evidencija vremena',
+// TODO: retranslate form.mail.footer as the English string has changed.
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
'form.mail.footer' => 'Anuko Time Tracker je jednostavan i lak za korišćenje za praćenje radnog vremena. Posetite www.anuko.com za više informacija.',
'form.mail.report_sent' => 'Izveštaj poslat.',
'form.mail.invoice_sent' => 'RaÄun poslat.',
@@ -690,21 +667,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/sv.lang.php b/WEB-INF/resources/sv.lang.php
index dd3981f36..dba0fd6f2 100644
--- a/WEB-INF/resources/sv.lang.php
+++ b/WEB-INF/resources/sv.lang.php
@@ -1,32 +1,9 @@
'Tillägg',
'menu.time' => 'Tider',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => 'Kostnader',
'menu.reports' => 'Rapporter',
@@ -59,8 +37,6 @@
'menu.tasks' => 'Arbetsuppgifter',
'menu.users' => 'Användare',
'menu.groups' => 'Grupper',
-// TODO: translate the following.
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => 'Exportera',
'menu.clients' => 'Kunder',
'menu.options' => 'Alternativ',
@@ -90,6 +66,9 @@
// TODO: translate the following.
// 'error.record' => 'Select record.',
'error.auth' => 'Ogiltigt användarnamn eller lösenord.',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => 'Det finns redan en användare med det här användarnamnet.',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -118,7 +97,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -146,10 +124,13 @@
'button.export' => 'Exportera grupp',
'button.import' => 'Importera grupp',
'button.close' => 'Stäng',
+// TODO: translate the following.
+// 'button.start' => 'Start',
'button.stop' => 'Avsluta',
// TODO: translate the following.
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -209,6 +190,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
'label.language' => 'Språk',
'label.decimal_mark' => 'Decimaltecken',
@@ -227,9 +209,6 @@
'label.ldap_hint' => 'Fyll i ditt användarnamn och lösenord för Windows i fälten nedan.',
'label.required_fields' => '* - Obligatoriska fält',
'label.on_behalf' => 'agerar som',
-'label.role_manager' => '(Ansvarig)',
-'label.role_comanager' => '(Delansvarig)',
-'label.role_admin' => '(Administratör)',
'label.page' => 'Sida',
'label.condition' => 'Villkor',
// TODO: translate the following.
@@ -255,9 +234,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Visa endast summeringar',
@@ -274,21 +253,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
'label.active_users' => 'Aktiva användare',
'label.inactive_users' => 'Inaktiva användare',
-// TODO: translate the following.
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -302,9 +268,10 @@
// TODO: Translate the following.
// 'title.success' => 'Success',
'title.login' => 'Logga in',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => 'Grupper',
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
'title.edit_group' => 'Redigera grupp',
'title.delete_group' => 'Ta bort grupp',
@@ -315,6 +282,7 @@
'title.delete_time_record' => 'Ta bort tidsregistrering',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
'title.expenses' => 'Kostnader',
'title.edit_expense' => 'Redigera kostnad',
'title.delete_expense' => 'Ta bort kostnad',
@@ -399,22 +367,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -445,7 +397,6 @@
'dropdown.delete' => 'Ta bort',
'dropdown.do_not_delete' => 'Ta inte bort',
// TODO: translate the following.
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -460,13 +411,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Glömt lösenordet?',
+ // TODO: re-translate form.login.about as it has changed.
+ // 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
'form.login.about' => 'Anuko Time Tracker är en lättanvänd applikation byggd med öppen källkod som enkelt låter dig spåra och hålla koll på arbetstider.',
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
+
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Begäran om att återställa lösenordet skickades via e-post.',
'form.reset_password.email_subject' => 'Återställning av lösenord för Anuko Time Tracker begärd',
-// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
'form.reset_password.email_body' => "Kära användare,\n\Någon, IP %s, begärde att ditt lösenord för Anuko Time Tracker skulle återställas. Vänligen besök den här länken ifall du vill återställa ditt lösenord.\n\n%s\n\nAnuko Time Tracker är en lättanvänd applikation byggd med öppen källkod som enkelt låter dig spåra och hålla koll på arbetstider. Besök https://www.anuko.com för mer information.\n\n",
@@ -503,10 +466,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Välj intervall',
'form.reports.set_period' => 'eller ställ in datum',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Visa fält',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Gruppera efter',
'form.reports.group_by_no' => '--- Ingen gruppering ---',
'form.reports.group_by_date' => 'Datum',
@@ -519,6 +485,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
'form.report.export' => 'Exportera som',
// TODO: translate the following.
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -532,8 +499,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Fakturanummer',
'form.invoice.person' => 'Person',
@@ -556,6 +523,8 @@
'form.tasks.inactive_tasks' => 'Inaktiva arbetsuppgifter',
// Users form. See example at https://timetracker.anuko.com/users.php
+// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
'form.users.uncompleted_entry' => 'Användaren har en oavslutad tidsregistrering',
'form.users.role' => 'Roll',
'form.users.manager' => 'Ansvarig',
@@ -616,14 +585,20 @@
'form.group_edit.type_duration' => 'Varaktighet',
// TODO: translate the following.
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
'form.group_edit.uncompleted_indicators' => 'Indikatorer för oavslutad registrering',
// TODO: translate the following.
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -631,6 +606,8 @@
// Mail form. See example at https://timetracker.anuko.com/report_send.php when emailing a report.
'form.mail.to' => 'Till',
'form.mail.report_subject' => 'Tidsrapport',
+// TODO: retranslate form.mail.footer as the English string has changed.
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
'form.mail.footer' => 'Anuko Time Tracker är en lättanvänd applikation byggd med öppen källkod för att enkelt spåra och hålla koll på arbetstider. Besök www.anuko.com för mer information.',
'form.mail.report_sent' => 'Rapporten skickades.',
'form.mail.invoice_sent' => 'Fakturan skickades.',
@@ -688,21 +665,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/tr.lang.php b/WEB-INF/resources/tr.lang.php
index 9475ad0d2..f2531ee76 100644
--- a/WEB-INF/resources/tr.lang.php
+++ b/WEB-INF/resources/tr.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => 'Zaman',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'Raporlar',
@@ -65,7 +43,6 @@
'menu.users' => 'Kullanıcılar',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
// 'menu.export' => 'Export',
'menu.clients' => 'Müşteriler',
// TODO: translate the following.
@@ -105,6 +82,8 @@
// 'error.record' => 'Select record.',
'error.auth' => 'Hatalı kullanıcı adı veya parola.',
// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
// 'error.user_exists' => 'User with this login already exists.',
// 'error.object_exists' => 'Object with this name already exists.',
// 'error.invoice_exists' => 'Invoice with this number already exists.',
@@ -128,7 +107,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -160,9 +138,11 @@
'button.import' => 'Ekibi içeri aktar', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -230,6 +210,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID',
// TODO: translate the following.
// 'label.language' => 'Language',
@@ -251,9 +232,6 @@
// 'label.ldap_hint' => 'Type your Windows login and password in the fields below.',
'label.required_fields' => '* zorunlu bilgi',
'label.on_behalf' => 'adına',
-'label.role_manager' => '(yönetici)',
-'label.role_comanager' => '(yardımcı yönetici)',
-'label.role_admin' => '(sistem yönetici)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -278,9 +256,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
'label.totals_only' => 'Sadece toplamlar',
@@ -297,20 +275,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -329,9 +295,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => 'GiriÅŸ',
-'title.groups' => 'Ekipler', // TODO: change "teams" to "groups".
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
+ 'title.groups' => 'Ekipler', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'Ekibi sil', // TODO: change "team" to "group".
@@ -343,6 +310,7 @@
'title.delete_time_record' => 'Zaman kaydını siliyor',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -427,22 +395,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -475,7 +427,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -486,16 +437,26 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => 'Parolanızı unuttunuz mu?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => 'Parola sıfırlama talebi yollandı.', // TODO: add "by email" to match the English string.
'form.reset_password.email_subject' => 'Anuko Time Tracker parola sıfırlama talebi',
// TODO: translate the ending of the following.
-// TODO: English string has changed. "from IP" added. Re-translate the beginning.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// TODO: English string has changed. Re-translate.
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// "IP %s" probably sounds awkward.
-'form.reset_password.email_body' => "Sayın Kullanıcı,\n\nBirisi, IP %s, Anuko Time Tracker parolanızın sıfırlanmasını istedi. Parolanızı sıfırlamak isterseniz lütfen bu bağlantıyı takip edin.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+'form.reset_password.email_body' => "Sayın Kullanıcı,\n\nBirisi, IP %s, Anuko Time Tracker parolanızın sıfırlanmasını istedi. Parolanızı sıfırlamak isterseniz lütfen bu bağlantıyı takip edin.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -533,10 +494,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => 'Zaman aralığını seç',
'form.reports.set_period' => 'ya da tarihleri belirle',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => 'Alanları göster',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => 'Gruplandırma kıstas',
'form.reports.group_by_no' => '--- gruplama yok ---',
'form.reports.group_by_date' => 'tarih',
@@ -551,6 +515,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
// TODO: translate the following.
// 'form.report.export' => 'Export',
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -564,8 +529,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'Fatura numarası',
'form.invoice.person' => 'KiÅŸi',
@@ -591,6 +556,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => 'Rol',
// TODO: translate the following.
@@ -655,13 +621,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -670,7 +642,7 @@
'form.mail.to' => 'Kime',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'Fatura yollandı.',
@@ -728,21 +700,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/zh-cn.lang.php b/WEB-INF/resources/zh-cn.lang.php
index ed76b599a..d30515863 100644
--- a/WEB-INF/resources/zh-cn.lang.php
+++ b/WEB-INF/resources/zh-cn.lang.php
@@ -1,32 +1,9 @@
'Plugins',
'menu.time' => '时间记录',
// TODO: translate the following.
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
'menu.expenses' => '费用',
'menu.reports' => '报告',
@@ -61,7 +39,6 @@
'menu.users' => '用户',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => '导出数æ®',
'menu.clients' => '客户',
'menu.options' => '选项',
@@ -92,6 +69,9 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
'error.auth' => '䏿£ç¡®çš„ç”¨æˆ·åæˆ–密ç 。',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => '该用户登录信æ¯å·²ç»å˜åœ¨ã€‚',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -118,7 +98,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -149,9 +128,11 @@
'button.import' => '导入团队信æ¯', // TODO: replace "team" with "group".
'button.close' => 'å…³é—',
// TODO: translate the following.
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -216,6 +197,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'IDå·',
'label.language' => 'è¯è¨€',
// TODO: translate the following.
@@ -238,9 +220,6 @@
'label.ldap_hint' => '在下é¢çš„æ ç›®è¾“å…¥æ‚¨çš„Windows用户å和密ç 。',
'label.required_fields' => '* å¿…å¡«æ ç›®',
'label.on_behalf' => '代表',
-'label.role_manager' => '(ç»ç†)',
-'label.role_comanager' => '(åˆä½œç»ç†äºº)',
-'label.role_admin' => '(管ç†å‘˜)',
'label.page' => '页ç ',
// TODO: translate the following.
// 'label.condition' => 'Condition',
@@ -265,9 +244,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
// 'label.totals_only' => 'Totals only',
@@ -283,20 +262,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -310,9 +277,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => '登录',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => '团队', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => 'åˆ é™¤å›¢é˜Ÿ', // TODO: change "team" to "group".
@@ -324,6 +292,7 @@
'title.delete_time_record' => 'åˆ é™¤æ—¶é—´è®°å½•',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -409,22 +378,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -456,7 +409,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -466,13 +418,25 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => '忘记密ç ?',
+// TODO: re-translate form.login.about as it has changed.
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
'form.login.about' => 'Anuko Time Tracker 是一ç§ç®€å•ã€æ˜“用ã€å¼€æ”¾æºä»£ç 的实时跟踪系统。',
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
+
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => '密ç é‡è®¾è¯·æ±‚å·²ç»å‘é€ã€‚', // TODO: Add "by email" to match the English string.
'form.reset_password.email_subject' => 'Anuko时间追踪器密ç é‡è®¾è¯·æ±‚',
// TODO: translate the following.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -508,10 +472,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => '选择时间段',
'form.reports.set_period' => '或设定日期',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => '显示æ ç›®',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => '分组方å¼',
'form.reports.group_by_no' => '--- 没有分组 ---',
'form.reports.group_by_date' => '日期',
@@ -526,6 +493,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
// TODO: translate the following.
// 'form.report.export' => 'Export',
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -539,8 +507,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => 'å‘票å·ç ',
'form.invoice.person' => '人', // TODO: is this correct?
@@ -566,6 +534,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => '角色',
'form.users.manager' => 'ç»ç†',
@@ -627,13 +596,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -642,7 +617,7 @@
'form.mail.to' => '到',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => 'å‘票已é€å‡ºã€‚',
@@ -700,21 +675,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/resources/zh-tw.lang.php b/WEB-INF/resources/zh-tw.lang.php
index 913c12cf1..890244f66 100644
--- a/WEB-INF/resources/zh-tw.lang.php
+++ b/WEB-INF/resources/zh-tw.lang.php
@@ -1,32 +1,9 @@
'Group',
// 'menu.plugins' => 'Plugins',
// 'menu.time' => 'Time',
+// 'menu.puncher' => 'Punch',
// 'menu.week' => 'Week',
// 'menu.expenses' => 'Expenses',
'menu.reports' => 'å ±å‘Š',
@@ -61,7 +39,6 @@
'menu.users' => '用戶',
// TODO: translate the following.
// 'menu.groups' => 'Groups',
-// 'menu.subgroups' => 'Subgroups',
'menu.export' => '輸出資料',
'menu.clients' => '客戶',
'menu.options' => 'é¸é …',
@@ -95,6 +72,9 @@
// 'error.report' => 'Select report.',
// 'error.record' => 'Select record.',
'error.auth' => '䏿£ç¢ºçš„ç”¨æˆ¶åæˆ–密碼。',
+// TODO: translate the following.
+// 'error.2fa_code' => 'Invalid 2FA code.',
+// 'error.weak_password' => 'Weak password.',
'error.user_exists' => '該使用者登錄資訊已經å˜åœ¨ã€‚',
// TODO: translate the following.
// 'error.object_exists' => 'Object with this name already exists.',
@@ -122,7 +102,6 @@
// 'error.user_count' => 'Limit on user count.',
// 'error.expired' => 'Expiration date reached.',
// 'error.file_storage' => 'File storage server error.', // See comment in English file.
-// 'error.remote_work' => 'Remote work server error.', // See comment in English file.
// Warning messages.
// TODO: translate the following.
@@ -153,9 +132,11 @@
'button.import' => '輸入團隊資訊', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
+// 'button.start' => 'Start',
// 'button.stop' => 'Stop',
// 'button.approve' => 'Approve',
// 'button.disapprove' => 'Disapprove',
+// 'button.sync' => 'Sync', // Used in Android app. The meaning is to synchronize offline time records with server.
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
@@ -221,6 +202,7 @@
// TODO: translate the following.
// 'label.day_view' => 'Day view',
// 'label.week_view' => 'Week view',
+// 'label.puncher' => 'Puncher',
'label.id' => 'ID號',
'label.language' => '語言',
// TODO: translate the following.
@@ -243,9 +225,6 @@
'label.ldap_hint' => '在下麵的欄目輸入您的Windows用戶å和密碼。',
'label.required_fields' => '* 必填欄目',
'label.on_behalf' => '代表',
-'label.role_manager' => '(ç¶“ç†)',
-'label.role_comanager' => '(åˆä½œç¶“ç†äºº)',
-'label.role_admin' => '(管ç†å“¡)',
// TODO: translate the following.
// 'label.page' => 'Page',
// 'label.condition' => 'Condition',
@@ -270,9 +249,9 @@
// 'label.paid_status' => 'Paid status',
// 'label.paid' => 'Paid',
// 'label.mark_paid' => 'Mark paid',
-// 'label.week_menu' => 'Week menu',
// 'label.week_note' => 'Week note',
// 'label.week_list' => 'Week list',
+// 'label.weekends' => 'Weekends',
// 'label.work_units' => 'Work units',
// 'label.work_units_short' => 'Units',
// 'label.totals_only' => 'Totals only',
@@ -288,20 +267,8 @@
// 'label.attachments' => 'Attachments',
// 'label.files' => 'Files',
// 'label.file' => 'File',
-// 'label.image' => 'Image',
-// 'label.download' => 'Download',
// 'label.active_users' => 'Active Users',
// 'label.inactive_users' => 'Inactive Users',
-// 'label.details' => 'Details',
-// 'label.budget' => 'Budget',
-// 'label.work' => 'Work', // Table column header for work items, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.offer' => 'Offer', // Table column header for offers, see https://www.anuko.com/time_tracker/what_is/work_plugin.htm
-// 'label.contractor' => 'Contractor', // Table column header for offers (contractor is someone who offers to do work).
- // Technically, it is either an org name or a combination of org and group names
- // because both work items and offers are owned by Time Tracker groups of users.
-// 'label.how_to_pay' => 'How to pay', // Label for the "How to pay" field on offers, which allows contractors to specify
- // how to pay them, for example: paypal email, check by mail to a specific address, etc.
-// 'label.moderator_comment' => 'Moderator comment', // Label for "Moderator comment" field that explains something.
// Entity names. We use lower case (in English) because they are used in dropdowns, too.
// They are used to associate a custom field with an entity type.
@@ -315,9 +282,10 @@
// 'title.error' => 'Error',
// 'title.success' => 'Success',
'title.login' => '登錄',
+// TODO: translate the follolwing.
+// 'title.2fa' => 'Two Factor Authentication',
'title.groups' => '團隊', // TODO: change "teams" to "groups".
// TODO: translate the following.
-// 'title.subgroups' => 'Subgroups',
// 'title.add_group' => 'Adding Group',
// 'title.edit_group' => 'Editing Group',
'title.delete_group' => '刪除團隊', // TODO: change "team" to "group".
@@ -329,6 +297,7 @@
'title.delete_time_record' => '刪除時間記錄',
// TODO: Translate the following.
// 'title.time_files' => 'Time Record Files',
+// 'title.puncher' => 'Puncher',
// 'title.expenses' => 'Expenses',
// 'title.edit_expense' => 'Editing Expense Item',
// 'title.delete_expense' => 'Deleting Expense Item',
@@ -413,22 +382,6 @@
// 'title.edit_file' => 'Editing File',
// 'title.delete_file' => 'Deleting File',
// 'title.download_file' => 'Downloading File',
-// 'title.work' => 'Work',
-// 'title.add_work' => 'Adding Work',
-// 'title.edit_work' => 'Editing Work',
-// 'title.delete_work' => 'Deleting Work',
-// 'title.active_work' => 'Active Work', // Active work items this group outsources to other groups.
-// 'title.available_work' => 'Available Work', // Available work items from other organizations.
-// 'title.inactive_work' => 'Inactive Work', // Inactive work items this group was outsourcing to other groups.
-// 'title.pending_work' => 'Pending Work', // Work items pending moderator approval.
-// 'title.offer' => 'Offer',
-// 'title.add_offer' => 'Adding Offer',
-// 'title.edit_offer' => 'Editing Offer',
-// 'title.delete_offer' => 'Deleting Offer',
-// 'title.active_offers' => 'Active Offers', // Active offers this group makes available to other groups.
-// 'title.available_offers' => 'Available Offers', // Available offers from other organizations.
-// 'title.inactive_offers' => 'Inactive Offers', // Inactive offers for group.
-// 'title.pending_offers' => 'Pending Offers', // Offers pending moderator approval.
// Section for common strings inside combo boxes on forms. Strings shared between forms shall be placed here.
// Strings that are used in a single form must go to the specific form section.
@@ -460,7 +413,6 @@
// 'dropdown.status_inactive' => 'inactive',
// 'dropdown.delete' => 'delete',
// 'dropdown.do_not_delete' => 'do not delete',
-// 'dropdown.pending_approval' => 'pending approval',
// 'dropdown.approved' => 'approved',
// 'dropdown.not_approved' => 'not approved',
// 'dropdown.paid' => 'paid',
@@ -471,13 +423,23 @@
// Login form. See example at https://timetracker.anuko.com/login.php.
'form.login.forgot_password' => '忘記密碼?',
// TODO: translate the following.
-// 'form.login.about' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system.',
+// 'form.login.about' => 'Anuko Time Tracker is an open source time tracking system.',
+
+// Email subject and body for two-factor authentication.
+// TODO: translate the following.
+// 'email.2fa_code.subject' => 'Anuko Time Tracker two-factor authentication code',
+// 'email.2fa_code.body' => "Dear User,\n\nYour two-factor authentication code is:\n\n%s\n\n",
+
+// Two-factor authentication form. See example at https://timetracker.anuko.com/2fa.php.
+// TODO: translate the following.
+// 'form.2fa.hint' => 'Check your email for 2FA code and enter it here.',
+// 'form.2fa.2fa_code' => '2FA code',
// Resetting Password form. See example at https://timetracker.anuko.com/password_reset.php.
'form.reset_password.message' => '密碼é‡è¨è«‹æ±‚已經發é€ã€‚', // TODO: Add "by email" to match the English string.
'form.reset_password.email_subject' => 'Anuko時間追蹤器密碼é‡è¨è«‹æ±‚',
// TODO: translate the following.
-// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is a simple, easy to use, open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
+// 'form.reset_password.email_body' => "Dear User,\n\nSomeone from IP %s requested your Anuko Time Tracker password reset. Please visit this link if you want to reset your password.\n\n%s\n\nAnuko Time Tracker is an open source time tracking system. Visit https://www.anuko.com for more information.\n\n",
// Changing Password form. See example at https://timetracker.anuko.com/password_change.php?ref=1.
// TODO: translate the following.
@@ -513,10 +475,13 @@
// 'form.reports.include_pending' => 'pending',
'form.reports.select_period' => '鏿“‡æ™‚間段',
'form.reports.set_period' => '或è¨å®šæ—¥æœŸ',
+// TODO: translate the following.
+// 'form.reports.note_containing' => 'Note containing',
'form.reports.show_fields' => '顯示欄目',
// TODO: translate the following.
// 'form.reports.time_fields' => 'Time fields',
// 'form.reports.user_fields' => 'User fields',
+// 'form.reports.project_fields' => 'Project fields',
'form.reports.group_by' => '分組方å¼',
'form.reports.group_by_no' => '--- 沒有分組 ---',
'form.reports.group_by_date' => '日期',
@@ -531,6 +496,7 @@
// (after generating a report at https://timetracker.anuko.com/reports.php).
// TODO: translate the following.
// 'form.report.export' => 'Export',
+// 'form.report.per_hour' => 'Per hour',
// 'form.report.assign_to_invoice' => 'Assign to invoice',
// 'form.report.assign_to_timesheet' => 'Assign to timesheet',
@@ -544,8 +510,8 @@
// 'form.templates.active_templates' => 'Active Templates',
// 'form.templates.inactive_templates' => 'Inactive Templates',
-// Invoice form. See example at https://timetracker.anuko.com/invoice.php
-// (you can get to this form after generating a report).
+// Invoice form. See example at https://timetracker.anuko.com/invoice_view.php
+// (you can get to this form after generating an invoice).
'form.invoice.number' => '發票號碼',
'form.invoice.person' => '人', // TODO: is this correct?
@@ -571,6 +537,7 @@
// Users form. See example at https://timetracker.anuko.com/users.php
// TODO: translate the following.
+// 'form.users.uncompleted_entry_today' => 'User has an uncompleted time entry today',
// 'form.users.uncompleted_entry' => 'User has an uncompleted time entry',
'form.users.role' => '角色',
'form.users.manager' => 'ç¶“ç†',
@@ -632,13 +599,19 @@
// 'form.group_edit.type_start_finish' => 'start and finish',
// 'form.group_edit.type_duration' => 'duration',
// 'form.group_edit.punch_mode' => 'Punch mode',
+// 'form.group_edit.one_uncompleted' => 'One uncompleted',
// 'form.group_edit.allow_overlap' => 'Allow overlap',
// 'form.group_edit.future_entries' => 'Future entries',
// 'form.group_edit.uncompleted_indicators' => 'Uncompleted indicators',
// 'form.group_edit.confirm_save' => 'Confirm saving',
-// 'form.group_edit.allow_ip' => 'Allow IP',
// 'form.group_edit.advanced_settings' => 'Advanced settings',
+// Advanced Group Settings form. See example at https://timetracker.anuko.com/group_advanced_edit.php.
+// TODO: Translate the following.
+// 'form.group_advanced_edit.allow_ip' => 'Allow IP',
+// 'form.group_advanced_edit.password_complexity' => 'Password complexity',
+// 'form.group_advanced_edit.2fa' => 'Two factor authentication',
+
// Deleting Group form. See example at https://timetracker.anuko.com/delete_group.php
// TODO: translate the following.
// 'form.group_delete.hint' => 'Are you sure you want to delete the entire group?',
@@ -647,7 +620,7 @@
'form.mail.to' => '到',
// TODO: translate the following.
// 'form.mail.report_subject' => 'Time Tracker Report',
-// 'form.mail.footer' => 'Anuko Time Tracker is a simple, easy to use, open source time tracking system. Visit www.anuko.com for more information.',
+// 'form.mail.footer' => 'Anuko Time Tracker is an open source time tracking system. Visit www.anuko.com for more information.',
// 'form.mail.report_sent' => 'Report sent.',
'form.mail.invoice_sent' => '發票已é€å‡ºã€‚',
@@ -705,21 +678,8 @@
// TODO: translate the following.
// 'form.display_options.note_on_separate_row' => 'Note on separate row',
// 'form.display_options.not_complete_days' => 'Not complete days',
+// 'form.display_options.inactive_projects' => 'Inactive projects',
+// 'form.display_options.cost_per_hour' => 'Cost per hour',
// 'form.display_options.custom_css' => 'Custom CSS',
-
-// Work plugin strings. See example at https://timetracker.anuko.com/work.php
-// TODO: translate the following.
-// 'work.error.work_not_available' => 'Work item is not available.',
-// 'work.error.offer_not_available' => 'Offer is not available.',
-// 'work.type.one_time' => 'one time', // Work type is "one time job" for well defined work ("do exactly this").
-// 'work.type.ongoing' => 'ongoing', // Work type is "ongoing" for complex jobs (billed by the hour, multiple contractors, etc.)
-// 'work.label.own_work' => 'Own work',
-// 'work.label.own_offers' => 'Own offers',
-// 'work.label.offers' => 'Offers',
-// 'work.button.send_message' => 'Send message',
-// 'work.button.make_offer' => 'Make offer',
-// 'work.button.accept' => 'Accept',
-// 'work.button.decline' => 'Decline',
-// 'work.title.send_message' => 'Sending Message',
-// 'work.msg.message_sent' => 'Message sent.',
+// 'form.display_options.custom_translation' => 'Custom translation',
);
diff --git a/WEB-INF/templates/2fa.tpl b/WEB-INF/templates/2fa.tpl
new file mode 100644
index 000000000..d425cbc11
--- /dev/null
+++ b/WEB-INF/templates/2fa.tpl
@@ -0,0 +1,30 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
+ {$i18n.form.2fa.hint}
+{$forms.twoFactorAuthForm.open}
+
+ |
+
+ |
+ {$forms.twoFactorAuthForm.login.control} |
+
+ |
+ |
+
+ |
+ {$forms.twoFactorAuthForm.password.control} |
+
+ |
+ |
+
+ |
+ {$forms.twoFactorAuthForm.auth_code.control} |
+
+ |
+
+ | {$forms.twoFactorAuthForm.btn_login.control} |
+
+
+{$forms.twoFactorAuthForm.close}
+
diff --git a/WEB-INF/templates/admin_group_add.tpl b/WEB-INF/templates/admin_group_add.tpl
index 029b52545..17514e478 100644
--- a/WEB-INF/templates/admin_group_add.tpl
+++ b/WEB-INF/templates/admin_group_add.tpl
@@ -1,49 +1,53 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.groupForm.open}
-
+
+ |
-
-
-
- | {$i18n.label.group_name} (*): |
- {$forms.groupForm.group_name.control} |
-
-
- | {$i18n.label.language}: |
- {$forms.groupForm.lang.control} |
-
- | |
-
- | {$i18n.label.manager_name} (*): |
- {$forms.groupForm.manager_name.control} |
-
-
- | {$i18n.label.manager_login} (*): |
- {$forms.groupForm.manager_login.control} |
-
+ |
+ {$forms.groupForm.group_name.control} |
+
+ |
+ |
+
+ |
+ {$forms.groupForm.lang.control} |
+
+ |
+ |
+
+ |
+ {$forms.groupForm.manager_name.control} |
+
+ |
+ |
+
+ |
+ {$forms.groupForm.manager_login.control} |
+
+ |
{if !$auth_external}
-
- | {$i18n.label.password} (*): |
- {$forms.groupForm.password1.control} |
-
-
- | {$i18n.label.confirm_password} (*): |
- {$forms.groupForm.password2.control} |
-
+ |
+
+ |
+ {$forms.groupForm.password1.control} |
+
+ |
+ |
+
+ |
+ {$forms.groupForm.password2.control} |
+
+ |
{/if}
-
- | {$i18n.label.email}: |
- {$forms.groupForm.manager_email.control} |
-
-
- |
- {$i18n.label.required_fields} |
-
- | |
-
- | {$forms.groupForm.btn_submit.control} |
-
-
- |
+ |
+
+ |
+ {$forms.groupForm.manager_email.control} |
+ | {$i18n.label.required_fields} |
+ |
+{$forms.groupForm.btn_submit.control}
{$forms.groupForm.close}
diff --git a/WEB-INF/templates/admin_group_delete.tpl b/WEB-INF/templates/admin_group_delete.tpl
index 57164d4a8..a4205036e 100644
--- a/WEB-INF/templates/admin_group_delete.tpl
+++ b/WEB-INF/templates/admin_group_delete.tpl
@@ -1,20 +1,7 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.groupForm.open}
-
-
-
-
-
- | {$group_to_delete|escape} |
-
-
- | |
-
-
- | {$forms.groupForm.btn_delete.control} |
- {$forms.groupForm.btn_cancel.control} |
-
-
- |
-
-
+
+{$forms.groupForm.btn_delete.control} {$forms.groupForm.btn_cancel.control}
{$forms.groupForm.close}
diff --git a/WEB-INF/templates/admin_group_edit.tpl b/WEB-INF/templates/admin_group_edit.tpl
index 70443e327..15185163e 100644
--- a/WEB-INF/templates/admin_group_edit.tpl
+++ b/WEB-INF/templates/admin_group_edit.tpl
@@ -1,45 +1,47 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.groupForm.open}
-
+
+ |
-
-
-
- | {$i18n.label.group_name} (*): |
- {$forms.groupForm.group_name.control} |
-
- | |
-
- | {$i18n.label.manager_name} (*): |
- {$forms.groupForm.manager_name.control} |
-
-
- | {$i18n.label.manager_login} (*): |
- {$forms.groupForm.manager_login.control} |
-
+ |
+ {$forms.groupForm.group_name.control} |
+
+ |
+ |
+
+ |
+ {$forms.groupForm.manager_name.control} |
+
+ |
+ |
+
+ |
+ {$forms.groupForm.manager_login.control} |
+
+ |
{if !$auth_external}
-
- | {$i18n.label.password} (*): |
- {$forms.groupForm.password1.control} |
-
-
- | {$i18n.label.confirm_password} (*): |
- {$forms.groupForm.password2.control} |
-
+ |
+
+ |
+ {$forms.groupForm.password1.control} |
+
+ |
+ |
+
+ |
+ {$forms.groupForm.password2.control} |
+
+ |
{/if}
-
- | {$i18n.label.email}: |
- {$forms.groupForm.manager_email.control} |
-
-
- |
- {$i18n.label.required_fields} |
-
- | |
-
- | {$forms.groupForm.btn_save.control} {$forms.groupForm.btn_cancel.control} |
-
-
- |
+ |
+
+ |
+ {$forms.groupForm.manager_email.control} |
+ | {$i18n.label.required_fields} |
+ |
+{$forms.groupForm.btn_save.control} {$forms.groupForm.btn_cancel.control}
{$forms.groupForm.close}
diff --git a/WEB-INF/templates/admin_groups.tpl b/WEB-INF/templates/admin_groups.tpl
index af98c12fd..ef9d729ff 100644
--- a/WEB-INF/templates/admin_groups.tpl
+++ b/WEB-INF/templates/admin_groups.tpl
@@ -1,42 +1,36 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
-
- | {$i18n.form.groups.hint} |
-
-
-
+{$i18n.form.groups.hint}
+{if $groups}
+
-
-
+{/if}
+
+
+
diff --git a/WEB-INF/templates/admin_options.tpl b/WEB-INF/templates/admin_options.tpl
index bff36ff19..be5bc79e5 100644
--- a/WEB-INF/templates/admin_options.tpl
+++ b/WEB-INF/templates/admin_options.tpl
@@ -1,39 +1,41 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.optionsForm.open}
-
+
+ |
-
-
-
- | {$i18n.label.person_name} (*): |
- {$forms.optionsForm.name.control} |
-
-
- | {$i18n.label.login} (*): |
- {$forms.optionsForm.login.control} |
-
+ |
+ {$forms.optionsForm.name.control} |
+
+ |
+ |
+
+ |
+ {$forms.optionsForm.login.control} |
+
+ |
{if !$auth_external}
-
- | {$i18n.label.password}: |
- {$forms.optionsForm.password1.control} |
-
-
- | {$i18n.label.confirm_password}: |
- {$forms.optionsForm.password2.control} |
-
+ |
+
+ |
+ {$forms.optionsForm.password1.control} |
+
+ |
+ |
+
+ |
+ {$forms.optionsForm.password2.control} |
+
+ |
{/if}
-
- | {$i18n.label.email}: |
- {$forms.optionsForm.email.control} |
-
-
- |
- {$i18n.label.required_fields} |
-
-
- | {$forms.optionsForm.btn_submit.control} |
-
-
- |
+ |
+
+ |
+ {$forms.optionsForm.email.control} |
+ | {$i18n.label.required_fields} |
+ |
+{$forms.optionsForm.btn_submit.control}
{$forms.optionsForm.close}
diff --git a/WEB-INF/templates/cf_custom_field_add.tpl b/WEB-INF/templates/cf_custom_field_add.tpl
index 089e4b681..acf1f386c 100644
--- a/WEB-INF/templates/cf_custom_field_add.tpl
+++ b/WEB-INF/templates/cf_custom_field_add.tpl
@@ -1,35 +1,35 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.fieldForm.open}
-
+
+ |
-
-{if $user->can('manage_custom_fields')}
-
-
- | {$i18n.label.thing_name} (*): |
- {$forms.fieldForm.name.control} |
-
-
- | {$i18n.label.entity}: |
- {$forms.fieldForm.entity.control} {$i18n.label.what_is_it} |
-
-
- | {$i18n.label.type}: |
- {$forms.fieldForm.type.control} |
-
-
- |
- {$forms.fieldForm.required.control} |
-
-
- |
- |
-
-
- | {$forms.fieldForm.btn_add.control} |
-
-
-{/if}
+ | |
+ {$forms.fieldForm.name.control} |
+
+ |
+ |
+
+ |
+ {$forms.fieldForm.entity.control}
+
+ {$i18n.label.what_is_it}
|
+ |
+ |
+
+ |
+ {$forms.fieldForm.type.control} |
+
+ |
+
+ | |
+ |
+
+ |
+ | {$i18n.label.required_fields} |
+{$forms.fieldForm.btn_add.control}
{$forms.fieldForm.close}
diff --git a/WEB-INF/templates/cf_custom_field_delete.tpl b/WEB-INF/templates/cf_custom_field_delete.tpl
index fae6d804d..d8595735a 100644
--- a/WEB-INF/templates/cf_custom_field_delete.tpl
+++ b/WEB-INF/templates/cf_custom_field_delete.tpl
@@ -1,22 +1,7 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.fieldDeleteForm.open}
-
-
-
-{if $user->can('manage_custom_fields')}
-
-
- | {$field|escape} |
-
-
- | |
-
-
- | {$forms.fieldDeleteForm.btn_delete.control} |
- {$forms.fieldDeleteForm.btn_cancel.control} |
-
-
-{/if}
- |
-
-
+
+{$forms.fieldDeleteForm.btn_delete.control} {$forms.fieldDeleteForm.btn_cancel.control}
{$forms.fieldDeleteForm.close}
diff --git a/WEB-INF/templates/cf_custom_field_edit.tpl b/WEB-INF/templates/cf_custom_field_edit.tpl
index 62e2a267e..36bbd3dce 100644
--- a/WEB-INF/templates/cf_custom_field_edit.tpl
+++ b/WEB-INF/templates/cf_custom_field_edit.tpl
@@ -1,35 +1,35 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.fieldForm.open}
-
+
+ |
-
-{if $user->can('manage_custom_fields')}
-
-
- | {$i18n.label.thing_name} (*): |
- {$forms.fieldForm.name.control} |
-
-
- | {$i18n.label.entity}: |
- {$forms.fieldForm.entity.control} {$i18n.label.what_is_it} |
-
-
- | {$i18n.label.type}: |
- {$forms.fieldForm.type.control} |
-
-
- |
- {$forms.fieldForm.required.control} |
-
-
- |
- |
-
-
- | {$forms.fieldForm.btn_save.control} |
-
-
-{/if}
+ | |
+ {$forms.fieldForm.name.control} |
+
+ |
+ |
+
+ |
+ {$forms.fieldForm.entity.control}
+
+ {$i18n.label.what_is_it}
|
+ |
+ |
+
+ |
+ {$forms.fieldForm.type.control} |
+
+ |
+
+ | |
+ |
+
+ |
+ | {$i18n.label.required_fields} |
+{$forms.fieldForm.btn_save.control}
{$forms.fieldForm.close}
diff --git a/WEB-INF/templates/cf_custom_fields.tpl b/WEB-INF/templates/cf_custom_fields.tpl
index 6636d79e1..812943db8 100644
--- a/WEB-INF/templates/cf_custom_fields.tpl
+++ b/WEB-INF/templates/cf_custom_fields.tpl
@@ -1,47 +1,41 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.customFieldsForm.open}
-
+
+{$forms.customFieldsForm.btn_add.control}
{$forms.customFieldsForm.close}
diff --git a/WEB-INF/templates/cf_dropdown_option_add.tpl b/WEB-INF/templates/cf_dropdown_option_add.tpl
index bcc1cee72..5ba70387b 100644
--- a/WEB-INF/templates/cf_dropdown_option_add.tpl
+++ b/WEB-INF/templates/cf_dropdown_option_add.tpl
@@ -1,27 +1,16 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.optionAddForm.open}
-
+
+ |
-
-{if $user->can('manage_custom_fields')}
-
-
- | {$i18n.label.thing_name} (*): |
- {$forms.optionAddForm.name.control} |
-
-
- |
- {$i18n.label.required_fields} |
-
-
- |
- |
-
-
- | {$forms.optionAddForm.btn_add.control} |
-
-
-{/if}
- |
+ |
+ {$forms.optionAddForm.name.control} |
+ |
+ |
+ | {$i18n.label.required_fields} |
+{$forms.optionAddForm.btn_add.control}
{$forms.optionAddForm.close}
diff --git a/WEB-INF/templates/cf_dropdown_option_delete.tpl b/WEB-INF/templates/cf_dropdown_option_delete.tpl
index bec03cc32..8fb56d618 100644
--- a/WEB-INF/templates/cf_dropdown_option_delete.tpl
+++ b/WEB-INF/templates/cf_dropdown_option_delete.tpl
@@ -1,22 +1,7 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.optionDeleteForm.open}
-
-
-
-{if $user->can('manage_custom_fields')}
-
-
- | {$option|escape} |
-
-
- | |
-
-
- | {$forms.optionDeleteForm.btn_delete.control} |
- {$forms.optionDeleteForm.btn_cancel.control} |
-
-
-{/if}
- |
-
-
+
+{$forms.optionDeleteForm.btn_delete.control} {$forms.optionDeleteForm.btn_cancel.control}
{$forms.optionDeleteForm.close}
diff --git a/WEB-INF/templates/cf_dropdown_option_edit.tpl b/WEB-INF/templates/cf_dropdown_option_edit.tpl
index c2b0bae9c..f7f987cd8 100644
--- a/WEB-INF/templates/cf_dropdown_option_edit.tpl
+++ b/WEB-INF/templates/cf_dropdown_option_edit.tpl
@@ -1,27 +1,16 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.optionEditForm.open}
-
+
+ |
-
-{if $user->can('manage_custom_fields')}
-
-
- | {$i18n.label.thing_name} (*): |
- {$forms.optionEditForm.name.control} |
-
-
- |
- {$i18n.label.required_fields} |
-
-
- |
- |
-
-
- | {$forms.optionEditForm.btn_save.control} |
-
-
-{/if}
- |
+ |
+ {$forms.optionEditForm.name.control} |
+ |
+ |
+ | {$i18n.label.required_fields} |
+{$forms.optionEditForm.btn_save.control}
{$forms.optionEditForm.close}
diff --git a/WEB-INF/templates/cf_dropdown_options.tpl b/WEB-INF/templates/cf_dropdown_options.tpl
index 92b2d4dac..f7a6b28b5 100644
--- a/WEB-INF/templates/cf_dropdown_options.tpl
+++ b/WEB-INF/templates/cf_dropdown_options.tpl
@@ -1,39 +1,26 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
-
+
+
+
+
diff --git a/WEB-INF/templates/charts.tpl b/WEB-INF/templates/charts.tpl
index 8e05e1985..27d335ffb 100644
--- a/WEB-INF/templates/charts.tpl
+++ b/WEB-INF/templates/charts.tpl
@@ -1,37 +1,141 @@
-
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
+
+
{$forms.chartForm.open}
-
+{$forms.chartForm.date.control}
+
+ | | {$forms.chartForm.date.control} |
+ |
-{if $user_dropdown}
- | {$i18n.label.user}: {$forms.chartForm.user.control} |
- {if $chart_selector}
- {$i18n.form.charts.chart}: {$forms.chartForm.type.control} |
- {/if}
-{else}
- {if $chart_selector}
- {$i18n.form.charts.chart}: {$forms.chartForm.type.control} |
- {/if}
+ |
+ {$forms.chartForm.favorite_report.control} |
+
+ |
+{if $chart_selector}
+ |
+
+ |
+ {$forms.chartForm.type.control} |
+
+ |
{/if}
-
+{if isset($user_dropdown)}
+ |
+
+ |
+ {$forms.chartForm.user.control} |
+
+ |
+{/if}
+ |
+
+ |
+ {$forms.chartForm.interval.control} |
+ |
-
+
+
+
-  |
-
-
+  |
+
+
{section name=i loop=$totals}
{if $smarty.section.i.index <= 12}
- | {$totals[i].name|escape} |
+ | {$totals[i].name|escape} |
{/if}
{/section}
|
-
-
-
- | {$i18n.form.charts.interval}: {$forms.chartForm.interval.control} |
- | {$forms.chartForm.date.control} |
+
+
+
+
+
+
+
+ {section name=i loop=$totals}
+ {if $smarty.section.i.index <= 12}
+ | {$totals[i].name|escape} |
+ {/if}
+ {/section}
+
+ |
+
{$forms.chartForm.close}
diff --git a/WEB-INF/templates/charts2.tpl b/WEB-INF/templates/charts2.tpl
deleted file mode 100644
index 7f4c3844a..000000000
--- a/WEB-INF/templates/charts2.tpl
+++ /dev/null
@@ -1,82 +0,0 @@
-{* Copyright (c) Anuko International Ltd. https://www.anuko.com
-License: See license.txt *}
-
-
-
-{$forms.chartForm.open}
-{$forms.chartForm.date.control}
-
- | | {$forms.chartForm.date.control} |
-{if $user_dropdown}
- |
-
- |
- {$forms.chartForm.user.control} |
-
- |
-{/if}
- |
-
- |
- {$forms.chartForm.interval.control} |
-
- |
-{if $chart_selector}
- |
-
- |
- {$forms.chartForm.type.control} |
-
- |
-{/if}
-
-
-
-
-
-  |
-
-
- {section name=i loop=$totals}
- {if $smarty.section.i.index <= 12}
- | {$totals[i].name|escape} |
- {/if}
- {/section}
-
- |
-
-
-
-
-
-
-
-
- {section name=i loop=$totals}
- {if $smarty.section.i.index <= 12}
- | {$totals[i].name|escape} |
- {/if}
- {/section}
-
- |
-
-
-{$forms.chartForm.close}
diff --git a/WEB-INF/templates/client_add.tpl b/WEB-INF/templates/client_add.tpl
index db10ede45..ac7a63efc 100644
--- a/WEB-INF/templates/client_add.tpl
+++ b/WEB-INF/templates/client_add.tpl
@@ -1,37 +1,40 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.clientForm.open}
-
+
+ |
-
-
-
- | {$i18n.label.client_name} (*): |
- {$forms.clientForm.name.control} |
-
-
- | {$i18n.label.client_address}: |
- {$forms.clientForm.address.control} |
-
-
- | {$i18n.label.tax}, %: |
- {$forms.clientForm.tax.control} (0{$user->getDecimalMark()}00) |
-
-
- |
- {$i18n.label.required_fields} |
-
- | |
+ |
+ {$forms.clientForm.name.control} |
+
+ |
+ |
+
+ |
+ {$forms.clientForm.address.control} |
+
+ |
+ |
+
+ |
+ {$forms.clientForm.tax.control} (0{$user->getDecimalMark()}00) |
+
+ |
+ | {$i18n.label.required_fields} |
+ |
{if $show_projects}
-
- | {$i18n.label.projects}: |
- {$forms.clientForm.projects.control} |
-
- | |
+ |
+ | {$i18n.label.projects}: |
+
+ | {$i18n.label.projects}: |
+ {$forms.clientForm.projects.control} |
+
+ |
{/if}
-
- | {$forms.clientForm.btn_submit.control} |
-
-
- |
+
+ | {$forms.clientForm.btn_submit.control} |
+ |
{$forms.clientForm.close}
diff --git a/WEB-INF/templates/client_delete.tpl b/WEB-INF/templates/client_delete.tpl
index f40b94c12..47506f79b 100644
--- a/WEB-INF/templates/client_delete.tpl
+++ b/WEB-INF/templates/client_delete.tpl
@@ -1,25 +1,19 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.clientDeleteForm.open}
-
+
+ | {$i18n.form.client.client_to_delete}: |
-
-
-
- | {$i18n.form.client.client_to_delete}: |
- {$client_to_delete|escape} |
-
-
- | {$i18n.form.client.client_entries}: |
- {$forms.clientDeleteForm.delete_client_entries.control} |
-
-
- | |
-
-
- | {$forms.clientDeleteForm.btn_delete.control} |
- {$forms.clientDeleteForm.btn_cancel.control} |
-
-
- |
+ {$i18n.form.client.client_to_delete}: |
+ |
+
+ |
+ | {$i18n.form.client.client_entries}: |
+
+ | {$i18n.form.client.client_entries}: |
+ {$forms.clientDeleteForm.delete_client_entries.control} |
+{$forms.clientDeleteForm.btn_delete.control} {$forms.clientDeleteForm.btn_cancel.control}
{$forms.clientDeleteForm.close}
diff --git a/WEB-INF/templates/client_edit.tpl b/WEB-INF/templates/client_edit.tpl
index 2abf70dc1..39c965ae0 100644
--- a/WEB-INF/templates/client_edit.tpl
+++ b/WEB-INF/templates/client_edit.tpl
@@ -1,41 +1,43 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.clientForm.open}
-
+
+ |
-
-
-
- | {$i18n.label.client_name} (*): |
- {$forms.clientForm.name.control} |
-
-
- | {$i18n.label.client_address}: |
- {$forms.clientForm.address.control} |
-
-
- | {$i18n.label.tax}, %: |
- {$forms.clientForm.tax.control} (0{$user->getDecimalMark()}00) |
-
-
- | {$i18n.label.status}: |
- {$forms.clientForm.status.control} |
-
-
- |
- {$i18n.label.required_fields} |
-
- | |
+ |
+ {$forms.clientForm.name.control} |
+
+ |
+ |
+
+ |
+ {$forms.clientForm.address.control} |
+
+ |
+ |
+
+ |
+ {$forms.clientForm.tax.control} (0{$user->getDecimalMark()}00) |
+
+ |
+ |
+
+ |
+ {$forms.clientForm.status.control} |
+
+ |
+ | {$i18n.label.required_fields} |
+ |
{if $show_projects}
-
- | {$i18n.label.projects}: |
- {$forms.clientForm.projects.control} |
-
-{/if}
- | |
-
- | {$forms.clientForm.btn_save.control} {$forms.clientForm.btn_copy.control} |
-
-
- |
+ |
+ | {$i18n.label.projects}: |
+
+ | {$i18n.label.projects}: |
+ {$forms.clientForm.projects.control} |
+ |
+{/if}
+{$forms.clientForm.btn_save.control} {$forms.clientForm.btn_copy.control}
{$forms.clientForm.close}
diff --git a/WEB-INF/templates/clients.tpl b/WEB-INF/templates/clients.tpl
index 07b835c87..9f7d4064b 100644
--- a/WEB-INF/templates/clients.tpl
+++ b/WEB-INF/templates/clients.tpl
@@ -1,74 +1,62 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
-
-
-
{if $user->can('manage_clients')}
-
- {if $inactive_clients}
-
+ {if $inactive_clients}{/if}
+ {if $active_clients}
+
-
-
-
+
+
{if $inactive_clients}
-
+
{/if}
{else}
-
-
-
-
-
- {if $active_clients}
- {foreach $active_clients as $client}
-
- | {$client.name|escape} |
- {$client.address|escape} |
-
- {/foreach}
- {/if}
-
-{/if}
- |
+
+{/if}
diff --git a/WEB-INF/templates/display_options.tpl b/WEB-INF/templates/display_options.tpl
index 025b7d984..0d0418af9 100644
--- a/WEB-INF/templates/display_options.tpl
+++ b/WEB-INF/templates/display_options.tpl
@@ -1,36 +1,73 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.displayOptionsForm.open}
-
- | |
-
+
+
+ |
- |
- {$forms.displayOptionsForm.time_note_on_separate_row.control} {$i18n.label.what_is_it} |
+ |
+ {$forms.displayOptionsForm.time_note_on_separate_row.control}
+
+ {$i18n.label.what_is_it}
+ |
-
- |
- {$forms.displayOptionsForm.time_not_complete_days.control} {$i18n.label.what_is_it} |
+ |
+ |
+
+ |
+ {$forms.displayOptionsForm.time_not_complete_days.control}
+
+ {$i18n.label.what_is_it}
+ |
+ |
+ |
- |
- {$forms.displayOptionsForm.record_custom_fields.control} {$i18n.label.what_is_it} |
+ |
+ {$forms.displayOptionsForm.record_custom_fields.control}
+
+ {$i18n.label.what_is_it}
+ |
-
- | |
-
+ |
+ |
+
+ |
- |
- {$forms.displayOptionsForm.report_note_on_separate_row.control} {$i18n.label.what_is_it} |
+ |
+ {$forms.displayOptionsForm.report_note_on_separate_row.control}
+
+ {$i18n.label.what_is_it}
+ |
-
- | |
-
+ |
- | {$forms.displayOptionsForm.custom_css.control} |
+ |
+ {$forms.displayOptionsForm.report_inactive_projects.control}
+
+ {$i18n.label.what_is_it}
+ |
-
- | |
+ |
- | {$forms.displayOptionsForm.btn_save.control} |
+ |
+ {$forms.displayOptionsForm.report_cost_per_hour.control}
+
+ {$i18n.label.what_is_it}
+ |
+ |
+ |
+
+ | {$forms.displayOptionsForm.custom_css.control} |
+ | {$i18n.label.what_is_it} |
+ |
+ |
+
+ | {$forms.displayOptionsForm.custom_translation.control} |
+ | {$i18n.label.what_is_it} |
+ |
+{$forms.displayOptionsForm.btn_save.control}
{$forms.displayOptionsForm.close}
diff --git a/WEB-INF/templates/entity_files.tpl b/WEB-INF/templates/entity_files.tpl
index ab9564852..07a46443d 100644
--- a/WEB-INF/templates/entity_files.tpl
+++ b/WEB-INF/templates/entity_files.tpl
@@ -1,47 +1,47 @@
-
-
-
-
-
-
-
-{if $can_edit}
- |
- |
-{/if}
-
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{if $files}
+
-
+ {/foreach}
+{/if}
{if $can_edit}
+
{$forms.fileUploadForm.open}
-
+
+ |
+
+ |
+ {$forms.fileUploadForm.newfile.control} |
+
+ |
+ |
-
-
-
- | {$i18n.label.description}: |
- {$forms.fileUploadForm.description.control} |
- {$forms.fileUploadForm.newfile.control} |
-
- | {$forms.fileUploadForm.btn_submit.control} |
-
- |
+ |
+ {$forms.fileUploadForm.description.control} |
+ |
+ | {$forms.fileUploadForm.btn_submit.control} |
{$forms.fileUploadForm.close}
{/if}
+
+
+
diff --git a/WEB-INF/templates/expense_delete.tpl b/WEB-INF/templates/expense_delete.tpl
index 6e5bf12c8..a9ea04d10 100644
--- a/WEB-INF/templates/expense_delete.tpl
+++ b/WEB-INF/templates/expense_delete.tpl
@@ -1,39 +1,28 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.expenseItemForm.open}
-
-
-
-
+
{if $user->isPluginEnabled('cl')}
-
+ | {$i18n.label.client} |
{/if}
-
{if $show_project}
-
+ {$i18n.label.project} |
{/if}
-
-
+ {$i18n.label.item} |
+ {$i18n.label.cost} |
{if $user->isPluginEnabled('cl')}
- | {$expense_item.client_name|escape} |
+ {$expense_item.client_name|escape} |
{/if}
{if $show_project}
- {$expense_item.project_name|escape} |
+ {$expense_item.project_name|escape} |
{/if}
- {$expense_item.name|escape} |
- {$expense_item.cost} |
-
-
-
-
- | |
-
-
- | {$forms.expenseItemForm.delete_button.control} {$forms.expenseItemForm.cancel_button.control} |
+ {$expense_item.name|escape} |
+ {$expense_item.cost} |
-
-
-
+{$forms.expenseItemForm.delete_button.control} {$forms.expenseItemForm.cancel_button.control}
{$forms.expenseItemForm.close}
diff --git a/WEB-INF/templates/expense_edit.tpl b/WEB-INF/templates/expense_edit.tpl
index 671e868cf..fc5cef8cc 100644
--- a/WEB-INF/templates/expense_edit.tpl
+++ b/WEB-INF/templates/expense_edit.tpl
@@ -1,3 +1,6 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.expenseItemForm.open}
-
-
-
-
+
-
-
{if $user->isPluginEnabled('cl')}
-
- | {$i18n.label.client} {if $user->isOptionEnabled('client_required')}(*){/if}: |
- {$forms.expenseItemForm.client.control} |
-
+ |
+
+ |
+ {$forms.expenseItemForm.client.control} |
+
+ |
{/if}
{if $show_project}
-
- | {$i18n.label.project} (*): |
- {$forms.expenseItemForm.project.control} |
-
+ |
+
+ |
+ {$forms.expenseItemForm.project.control} |
+
+ |
{/if}
{if $predefined_expenses}
-
- | {$i18n.label.expense}: |
- {$forms.expenseItemForm.predefined_expense.control} |
-
-
- | {$i18n.label.quantity}: |
- {$forms.expenseItemForm.quantity.control} |
-
+ |
+
+ |
+ {$forms.expenseItemForm.predefined_expense.control} |
+
+ |
+ |
+
+ |
+ {$forms.expenseItemForm.quantity.control} |
+
+ |
{/if}
-
- | {$i18n.label.comment}: |
- {$forms.expenseItemForm.item_name.control} |
-
-
- | {$i18n.label.cost}: |
- {$forms.expenseItemForm.cost.control} {$user->getCurrency()|escape} |
-
+ |
+
+ |
+ {$forms.expenseItemForm.item_name.control} |
+
+ |
+ |
+
+ |
+ {$forms.expenseItemForm.cost.control} {$user->getCurrency()|escape} |
+
+ |
{if ($user->can('manage_invoices') && $user->isPluginEnabled('ps'))}
-
- | |
- |
-
+
+ |
+ |
+
{/if}
-
- | {$i18n.label.date}: |
- {$forms.expenseItemForm.date.control} |
-
-
- | |
-
-
- |
- {$forms.expenseItemForm.btn_save.control} {$forms.expenseItemForm.btn_copy.control} {$forms.expenseItemForm.btn_delete.control} |
-
-
- |
-
-
-
+ |
+
+ |
+ {$forms.expenseItemForm.date.control} |
+ |
+{$forms.expenseItemForm.btn_save.control} {$forms.expenseItemForm.btn_copy.control} {$forms.expenseItemForm.btn_delete.control}
{$forms.expenseItemForm.close}
diff --git a/WEB-INF/templates/expenses.tpl b/WEB-INF/templates/expenses.tpl
index 3c5867279..859ae3506 100644
--- a/WEB-INF/templates/expenses.tpl
+++ b/WEB-INF/templates/expenses.tpl
@@ -1,3 +1,6 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.expensesForm.open}
-
+{$forms.expensesForm.date.control}
+
+ | | {$forms.expensesForm.date.control} |
+{if isset($user_dropdown)}
+ |
-
-
-{if $user_dropdown}
-
- | {$i18n.label.user}: |
- {$forms.expensesForm.user.control} |
-
+ |
+ {$forms.expensesForm.user.control} |
+
+ |
{/if}
{if $user->isPluginEnabled('cl')}
-
- | {$i18n.label.client}{if $user->isOptionEnabled('client_required')} (*){/if}: |
- {$forms.expensesForm.client.control} |
-
+ |
+
+ |
+ {$forms.expensesForm.client.control} |
+
+ |
{/if}
{if $show_project}
-
- | {$i18n.label.project} (*): |
- {$forms.expensesForm.project.control} |
-
+ |
+
+ |
+ {$forms.expensesForm.project.control} |
+
+ |
{/if}
{if $predefined_expenses}
-
- | {$i18n.label.expense}: |
- {$forms.expensesForm.predefined_expense.control} |
-
-
- | {$i18n.label.quantity}: |
- {$forms.expensesForm.quantity.control} |
-
+ |
+
+ |
+ {$forms.expensesForm.predefined_expense.control} |
+
+ |
+ |
+
+ |
+ {$forms.expensesForm.quantity.control} |
+
+ |
{/if}
-
- | {$i18n.label.comment} (*): |
- {$forms.expensesForm.item_name.control} |
-
-
- | {$i18n.label.cost} (*): |
- {$forms.expensesForm.cost.control} {$user->getCurrency()|escape} |
-
+ |
+
+ |
+ {$forms.expensesForm.item_name.control} |
+
+ |
+ |
+
+ |
+ {$forms.expensesForm.cost.control} |
+
+ |
{if $show_files}
-
- | {$i18n.label.file}: |
- {$forms.expensesForm.newfile.control} |
-
-{/if}
-
- |
-
-
- | {$forms.expensesForm.date.control} |
-
- |
+ |
+
+ |
+ {$forms.expensesForm.newfile.control} |
-
-
-
+ |
+{/if}
- | {$forms.expensesForm.btn_submit.control} |
+ {$forms.expensesForm.btn_submit.control} |
+{$forms.expensesForm.close}
-
-
-
{if $expense_items}
-
-
+
+
-
-
- | {$i18n.label.day_total}: {$user->getCurrency()|escape} {$day_total} |
-
-
-{/if}
-
-
-{$forms.expensesForm.close}
+
+{$i18n.label.day_total}: {$user->getCurrency()|escape} {$day_total}
+{/if}
+
diff --git a/WEB-INF/templates/export.tpl b/WEB-INF/templates/export.tpl
index 487f00978..171aa9b1b 100644
--- a/WEB-INF/templates/export.tpl
+++ b/WEB-INF/templates/export.tpl
@@ -1,23 +1,16 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
+{$i18n.form.export.hint}
+
{$forms.exportForm.open}
-
+
+ |
-
-{if $user->can('export_data')}
-
-
-
-
-
- {$i18n.form.export.hint}
|
- | |
-
- | {$i18n.form.export.compression}: |
- {$forms.exportForm.compression.control} |
-
- | {$forms.exportForm.btn_submit.control} |
-
-{/if}
- |
+ |
+ {$forms.exportForm.compression.control} |
+ |
+{$forms.exportForm.btn_submit.control}
{$forms.exportForm.close}
diff --git a/WEB-INF/templates/file_delete.tpl b/WEB-INF/templates/file_delete.tpl
index 81107daa5..80abe01ce 100644
--- a/WEB-INF/templates/file_delete.tpl
+++ b/WEB-INF/templates/file_delete.tpl
@@ -1,18 +1,7 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.fileDeleteForm.open}
-
-
-
-
-
- | {$file_to_delete|escape} |
-
- | |
-
- | {$forms.fileDeleteForm.btn_delete.control} |
- {$forms.fileDeleteForm.btn_cancel.control} |
-
-
- |
-
-
+
+{$forms.fileDeleteForm.btn_delete.control} {$forms.fileDeleteForm.btn_cancel.control}
{$forms.fileDeleteForm.close}
diff --git a/WEB-INF/templates/file_edit.tpl b/WEB-INF/templates/file_edit.tpl
index 697a650ce..66f72cc3d 100644
--- a/WEB-INF/templates/file_edit.tpl
+++ b/WEB-INF/templates/file_edit.tpl
@@ -1,29 +1,22 @@
+{* Copyright (c) Anuko International Ltd. https://www.anuko.com
+License: See license.txt *}
+
{$forms.fileForm.open}
-
+
+ |
-
-
-
- | {$i18n.label.thing_name} (*): |
- {$forms.fileForm.file_name.control} |
-
-
- | {$i18n.label.description}: |
- {$forms.fileForm.description.control} |
-
-
- |
- {$i18n.label.required_fields} |
-
-
- |
- |
-
-
- | {$forms.fileForm.btn_save.control} |
-
-
- |
+ |
+ {$forms.fileForm.file_name.control} |
+ |
+ |
+
+ |
+ {$forms.fileForm.description.control} |
+
+ |
+ | {$i18n.label.required_fields} |
+ |
+{$forms.fileForm.btn_save.control}
{$forms.fileForm.close}
diff --git a/WEB-INF/templates/footer.tpl b/WEB-INF/templates/footer.tpl
index a5ae56f90..8844f56e8 100644
--- a/WEB-INF/templates/footer.tpl
+++ b/WEB-INF/templates/footer.tpl
@@ -1,28 +1,7 @@
-
-
-
- |
-
+ {* page-content *}
-
-
-
-
+
+Anuko Time Tracker {constant('APP_VERSION')} | Copyright © Anuko
- |
-
-
| | | | | |