Compare commits
174 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
edfa404ed6 | ||
|
2d1d5d46f6 | ||
|
45fe6a6362 | ||
|
23f697f812 | ||
|
263181baa0 | ||
|
9132e222fe | ||
|
2bc108fe3e | ||
|
02d0121f4d | ||
|
b5acb4c49b | ||
|
cd05a95a0f | ||
|
2d2700cacb | ||
|
1bacd8e13d | ||
|
f6986fac18 | ||
|
8b6f882edc | ||
|
91d8eaeb74 | ||
|
8d2c3ae584 | ||
|
18e8fc8293 | ||
|
e1c702f3d0 | ||
|
71cede74a3 | ||
|
7b0bc9e472 | ||
|
8cb8611b4f | ||
|
c048f403e6 | ||
|
4aee175105 | ||
|
cf8604e984 | ||
|
cdf6ac78e2 | ||
|
70433aace5 | ||
|
247221950d | ||
|
866d6647d2 | ||
|
f1da3ef5e8 | ||
|
2cc4f4d382 | ||
|
6659a5cd08 | ||
|
21c221b520 | ||
|
55807bfc94 | ||
|
696e9b3e28 | ||
|
198216f38b | ||
|
27b46e1abf | ||
|
7380175093 | ||
|
1ad0360e42 | ||
|
2503590463 | ||
|
40e16db01f | ||
|
684aef0a42 | ||
|
dd9cae5482 | ||
|
7ee15946c7 | ||
|
6660e1ff73 | ||
|
2847908523 | ||
|
9b37c450ed | ||
|
003aea6047 | ||
|
9d1440fb45 | ||
|
832d83dfde | ||
|
90a0caf1dc | ||
|
d3c134e13f | ||
|
269ae34db3 | ||
|
8ff8c1ac5d | ||
|
2638bce851 | ||
|
72e6ed76bf | ||
|
8348438148 | ||
|
338a5016cf | ||
|
11b71e3af2 | ||
|
8c5c12cb47 | ||
|
8b977644f7 | ||
|
7595d640f5 | ||
|
14cd6ca3bf | ||
|
633b26bf7e | ||
|
1ead23cb87 | ||
|
6530d0f9df | ||
|
135ac118b0 | ||
|
70d51c757b | ||
|
ffad8bfa7f | ||
|
ffc5ba013f | ||
|
aaa054e0a5 | ||
|
54bf7ed659 | ||
|
6462dd8af6 | ||
|
079437384e | ||
|
10fcd9177c | ||
|
b0d38b87de | ||
|
d9470cb377 | ||
|
b4ce0555d9 | ||
|
9ba7ee54a7 | ||
|
cb24a7149f | ||
|
9abb92763d | ||
|
54d4c90ec4 | ||
|
76037d1f4e | ||
|
735743047f | ||
|
82c474d0ae | ||
|
0dc37fb361 | ||
|
734e174442 | ||
|
4086a63ebd | ||
|
f2a0b7cded | ||
|
bda40dfbb9 | ||
|
fbb0064505 | ||
|
4b02ac8f35 | ||
|
47c936e026 | ||
|
bcf963ac49 | ||
|
765ba77621 | ||
|
0f88eed08c | ||
|
766eae5a7a | ||
|
90b8ea15ff | ||
|
34ffb96ae3 | ||
|
74d745cfc4 | ||
|
cc9345136c | ||
|
5ba9bbbcd1 | ||
|
cae924eb81 | ||
|
187d48f93d | ||
|
9f833b9bd5 | ||
|
b856911f0f | ||
|
d18a8d8b56 | ||
|
416c138017 | ||
|
76cfe7fece | ||
|
7587ead732 | ||
|
69f8c237ff | ||
|
b8e15b990b | ||
|
35fb87ab1e | ||
|
acb81187d9 | ||
|
5153818b4e | ||
|
5c3809aa33 | ||
|
95d212a076 | ||
|
7133c85deb | ||
|
7ab59273da | ||
|
33ea1e56cf | ||
|
b7a6b91039 | ||
|
e646dd9332 | ||
|
30e5cc3bc3 | ||
|
e44f4802d5 | ||
|
9ef48e79cd | ||
|
3acad5056a | ||
|
44d6173569 | ||
|
9a0cad079c | ||
|
f5da53a761 | ||
|
f8fa5db3e7 | ||
|
5e189c8a4a | ||
|
9e3c68982b | ||
|
b3ed80d186 | ||
|
a4f7aac963 | ||
|
c45034e6b1 | ||
|
5ad4d9f421 | ||
|
eb135aee39 | ||
|
fe59fac1c3 | ||
|
26979a4321 | ||
|
a0e5f45da3 | ||
|
739379fabb | ||
|
96fff2e5f4 | ||
|
2471e78188 | ||
|
d23fda245e | ||
|
791a17fcad | ||
|
dabc48fed3 | ||
|
980778e599 | ||
|
68c5fd0617 | ||
|
7bbcec91aa | ||
|
c483c34598 | ||
|
906a9db628 | ||
|
5583074001 | ||
|
e4c8f6b023 | ||
|
4555bf3b63 | ||
|
2aca551692 | ||
|
f5eff8ab49 | ||
|
36f5fb23e9 | ||
|
33dcd17fbd | ||
|
3d82c9abbd | ||
|
779ac31ffe | ||
|
0a6c7d73a7 | ||
|
fc05044353 | ||
|
55ac768521 | ||
|
a455a01204 | ||
|
8b963ae0f1 | ||
|
a1adc80c29 | ||
|
760914bf82 | ||
|
42689ecefe | ||
|
c889416c0a | ||
|
bfb5525ec1 | ||
|
20380faeb3 | ||
|
5ecd3a585e | ||
|
bfa3347a20 | ||
|
e42f4b405d | ||
|
27169e1428 |
@@ -10,7 +10,7 @@ for /f "tokens=*" %%a in ('jq .Version versiontemp.json --raw-output') do set ve
|
||||
del versiontemp.json
|
||||
|
||||
del "%releasePath%\grocy_%version%.zip"
|
||||
7za a -r "%releasePath%\grocy_%version%.zip" "%projectPath%\*" -xr!.* -xr!build.bat -xr!composer.json -xr!composer.lock -xr!package.json -xr!yarn.lock
|
||||
7za a -r "%releasePath%\grocy_%version%.zip" "%projectPath%\*" -xr!.* -xr!build.bat -xr!composer.json -xr!composer.lock -xr!package.json -xr!yarn.lock -xr!docs
|
||||
7za a "%releasePath%\grocy_%version%.zip" "%projectPath%\public\.htaccess"
|
||||
7za rn "%releasePath%\grocy_%version%.zip" .htaccess public\.htaccess
|
||||
7za d "%releasePath%\grocy_%version%.zip" data\*.* data\storage data\viewcache\*
|
||||
|
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -3,7 +3,7 @@ name: Bug report
|
||||
about: If you've found something that does not work, please report it to help improve
|
||||
grocy
|
||||
title: 'Bug: '
|
||||
labels: bug, ui-bug
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
BIN
.github/publication_assets/chores.png
vendored
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 69 KiB |
BIN
.github/publication_assets/mealplan.png
vendored
Before Width: | Height: | Size: 637 KiB After Width: | Height: | Size: 496 KiB |
BIN
.github/publication_assets/shoppinglist.png
vendored
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 78 KiB |
BIN
.github/publication_assets/stock.png
vendored
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 111 KiB |
95
.php-cs-fixer.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
$finder = PhpCsFixer\Finder::create()
|
||||
->exclude(['vendor'])
|
||||
->ignoreVCSIgnored(true)
|
||||
->files()->name('*.php')
|
||||
->in(__DIR__)
|
||||
;
|
||||
|
||||
$cfg = new PhpCsFixer\Config();
|
||||
return $cfg
|
||||
->setRules([
|
||||
'@PSR2' => true,
|
||||
'array_indentation' => true,
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
'combine_consecutive_unsets' => true,
|
||||
'class_attributes_separation' => true,
|
||||
'multiline_whitespace_before_semicolons' => false,
|
||||
'single_quote' => true,
|
||||
// 'blank_line_after_opening_tag' => true,
|
||||
// 'blank_line_before_return' => true,
|
||||
'braces' => [
|
||||
'allow_single_line_closure' => true,
|
||||
'position_after_anonymous_constructs' => 'same',
|
||||
'position_after_control_structures' => 'next',
|
||||
'position_after_functions_and_oop_constructs' => 'next',
|
||||
],
|
||||
// 'cast_spaces' => true,
|
||||
// 'class_definition' => array('singleLine' => true),
|
||||
'concat_space' => ['spacing' => 'one'],
|
||||
'declare_equal_normalize' => true,
|
||||
'function_typehint_space' => true,
|
||||
'single_line_comment_style' => ['comment_types' => ['hash']],
|
||||
'include' => true,
|
||||
'lowercase_cast' => true,
|
||||
// 'native_function_casing' => true,
|
||||
// 'new_with_braces' => true,
|
||||
// 'no_blank_lines_after_class_opening' => true,
|
||||
// 'no_blank_lines_after_phpdoc' => true,
|
||||
// 'no_empty_comment' => true,
|
||||
// 'no_empty_phpdoc' => true,
|
||||
// 'no_empty_statement' => true,
|
||||
'no_leading_import_slash' => true,
|
||||
'no_leading_namespace_whitespace' => true,
|
||||
// 'no_mixed_echo_print' => array('use' => 'echo'),
|
||||
'no_multiline_whitespace_around_double_arrow' => true,
|
||||
// 'no_short_bool_cast' => true,
|
||||
// 'no_singleline_whitespace_before_semicolons' => true,
|
||||
'no_spaces_around_offset' => true,
|
||||
// 'no_trailing_comma_in_list_call' => true,
|
||||
// 'no_trailing_comma_in_singleline_array' => true,
|
||||
// 'no_unneeded_control_parentheses' => true,
|
||||
// 'no_unused_imports' => true,
|
||||
'no_whitespace_before_comma_in_array' => true,
|
||||
'no_whitespace_in_blank_line' => true,
|
||||
// 'normalize_index_brace' => true,
|
||||
'object_operator_without_whitespace' => true,
|
||||
// 'php_unit_fqcn_annotation' => true,
|
||||
// 'phpdoc_align' => true,
|
||||
// 'phpdoc_annotation_without_dot' => true,
|
||||
// 'phpdoc_indent' => true,
|
||||
// 'phpdoc_inline_tag' => true,
|
||||
// 'phpdoc_no_access' => true,
|
||||
// 'phpdoc_no_alias_tag' => true,
|
||||
// 'phpdoc_no_empty_return' => true,
|
||||
// 'phpdoc_no_package' => true,
|
||||
// 'phpdoc_no_useless_inheritdoc' => true,
|
||||
// 'phpdoc_return_self_reference' => true,
|
||||
// 'phpdoc_scalar' => true,
|
||||
// 'phpdoc_separation' => true,
|
||||
// 'phpdoc_single_line_var_spacing' => true,
|
||||
// 'phpdoc_summary' => true,
|
||||
// 'phpdoc_to_comment' => true,
|
||||
// 'phpdoc_trim' => true,
|
||||
// 'phpdoc_types' => true,
|
||||
// 'phpdoc_var_without_name' => true,
|
||||
// 'pre_increment' => true,
|
||||
// 'return_type_declaration' => true,
|
||||
// 'self_accessor' => true,
|
||||
// 'short_scalar_cast' => true,
|
||||
'single_blank_line_before_namespace' => true,
|
||||
// 'single_class_element_per_statement' => true,
|
||||
// 'space_after_semicolon' => true,
|
||||
// 'standardize_not_equals' => true,
|
||||
'ternary_operator_spaces' => true,
|
||||
// 'trailing_comma_in_multiline_array' => true,
|
||||
'trim_array_spaces' => true,
|
||||
'unary_operator_spaces' => true,
|
||||
'whitespace_after_comma_in_array' => true,
|
||||
])
|
||||
->setIndent("\t")
|
||||
->setLineEnding("\n")
|
||||
->setUsingCache(false)
|
||||
->setFinder($finder)
|
||||
;
|
97
.php_cs
@@ -1,97 +0,0 @@
|
||||
<?php
|
||||
|
||||
return PhpCsFixer\Config::create()
|
||||
->setRules(array(
|
||||
'@PSR2' => true,
|
||||
'array_indentation' => true,
|
||||
'array_syntax' => array('syntax' => 'short'),
|
||||
'combine_consecutive_unsets' => true,
|
||||
'method_separation' => true,
|
||||
'no_multiline_whitespace_before_semicolons' => true,
|
||||
'single_quote' => true,
|
||||
|
||||
'binary_operator_spaces' => array(
|
||||
'align_double_arrow' => false,
|
||||
'align_equals' => false,
|
||||
),
|
||||
// 'blank_line_after_opening_tag' => true,
|
||||
// 'blank_line_before_return' => true,
|
||||
'braces' => array(
|
||||
'allow_single_line_closure' => true,
|
||||
'position_after_anonymous_constructs' => 'same',
|
||||
'position_after_control_structures' => 'next',
|
||||
'position_after_functions_and_oop_constructs' => 'next',
|
||||
),
|
||||
// 'cast_spaces' => true,
|
||||
// 'class_definition' => array('singleLine' => true),
|
||||
'concat_space' => array('spacing' => 'one'),
|
||||
'declare_equal_normalize' => true,
|
||||
'function_typehint_space' => true,
|
||||
'hash_to_slash_comment' => true,
|
||||
'include' => true,
|
||||
'lowercase_cast' => true,
|
||||
// 'native_function_casing' => true,
|
||||
// 'new_with_braces' => true,
|
||||
// 'no_blank_lines_after_class_opening' => true,
|
||||
// 'no_blank_lines_after_phpdoc' => true,
|
||||
// 'no_empty_comment' => true,
|
||||
// 'no_empty_phpdoc' => true,
|
||||
// 'no_empty_statement' => true,
|
||||
'no_extra_consecutive_blank_lines' => array(
|
||||
'extra',
|
||||
'parenthesis_brace_block',
|
||||
'square_brace_block',
|
||||
'throw',
|
||||
'use',
|
||||
),
|
||||
'no_leading_import_slash' => true,
|
||||
'no_leading_namespace_whitespace' => true,
|
||||
// 'no_mixed_echo_print' => array('use' => 'echo'),
|
||||
'no_multiline_whitespace_around_double_arrow' => true,
|
||||
// 'no_short_bool_cast' => true,
|
||||
// 'no_singleline_whitespace_before_semicolons' => true,
|
||||
'no_spaces_around_offset' => true,
|
||||
// 'no_trailing_comma_in_list_call' => true,
|
||||
// 'no_trailing_comma_in_singleline_array' => true,
|
||||
// 'no_unneeded_control_parentheses' => true,
|
||||
// 'no_unused_imports' => true,
|
||||
'no_whitespace_before_comma_in_array' => true,
|
||||
'no_whitespace_in_blank_line' => true,
|
||||
// 'normalize_index_brace' => true,
|
||||
'object_operator_without_whitespace' => true,
|
||||
// 'php_unit_fqcn_annotation' => true,
|
||||
// 'phpdoc_align' => true,
|
||||
// 'phpdoc_annotation_without_dot' => true,
|
||||
// 'phpdoc_indent' => true,
|
||||
// 'phpdoc_inline_tag' => true,
|
||||
// 'phpdoc_no_access' => true,
|
||||
// 'phpdoc_no_alias_tag' => true,
|
||||
// 'phpdoc_no_empty_return' => true,
|
||||
// 'phpdoc_no_package' => true,
|
||||
// 'phpdoc_no_useless_inheritdoc' => true,
|
||||
// 'phpdoc_return_self_reference' => true,
|
||||
// 'phpdoc_scalar' => true,
|
||||
// 'phpdoc_separation' => true,
|
||||
// 'phpdoc_single_line_var_spacing' => true,
|
||||
// 'phpdoc_summary' => true,
|
||||
// 'phpdoc_to_comment' => true,
|
||||
// 'phpdoc_trim' => true,
|
||||
// 'phpdoc_types' => true,
|
||||
// 'phpdoc_var_without_name' => true,
|
||||
// 'pre_increment' => true,
|
||||
// 'return_type_declaration' => true,
|
||||
// 'self_accessor' => true,
|
||||
// 'short_scalar_cast' => true,
|
||||
'single_blank_line_before_namespace' => true,
|
||||
// 'single_class_element_per_statement' => true,
|
||||
// 'space_after_semicolon' => true,
|
||||
// 'standardize_not_equals' => true,
|
||||
'ternary_operator_spaces' => true,
|
||||
// 'trailing_comma_in_multiline_array' => true,
|
||||
'trim_array_spaces' => true,
|
||||
'unary_operator_spaces' => true,
|
||||
'whitespace_after_comma_in_array' => true,
|
||||
))
|
||||
->setIndent("\t")
|
||||
->setLineEnding("\n")
|
||||
;
|
2
.vscode/settings.json
vendored
@@ -14,4 +14,4 @@
|
||||
"php-cs-fixer.formatHtml": true,
|
||||
"php-cs-fixer.autoFixBySemicolon": true,
|
||||
"php-cs-fixer.onsave": true,
|
||||
}
|
||||
}
|
12
README.md
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
<img alt="Logo" height="50" src="https://raw.githubusercontent.com/grocy/grocy/master/public/img/grocy_logo.svg?sanitize=true"/>
|
||||
<img alt="Logo" height="50" src="https://raw.githubusercontent.com/grocy/grocy/master/public/img/grocy_logo.svg?sanitize=true" />
|
||||
<h3>ERP beyond your fridge</h3>
|
||||
<h5> grocy is a web-based self-hosted groceries & household management solution for your home</h5>
|
||||
<h4>grocy is a web-based self-hosted groceries & household management solution for your home<br>Created by <a href="https://github.com/berrnd">@berrnd</a></h4>
|
||||
</div>
|
||||
|
||||
-----
|
||||
@@ -21,10 +21,10 @@ Please don't send me private messages regarding grocy help. I check the issue tr
|
||||
See the website for a list of community contributed Add-ons / Tools: [https://grocy.info/addons](https://grocy.info/addons)
|
||||
|
||||
## Motivation
|
||||
A household needs to be managed. I did this so far (almost 10 years) with my first self written software (a C# windows forms application) and with a bunch of Excel sheets. The software is a pain to use and Excel is Excel. So I searched for and tried different things for a (very) long time, nothing 100 % fitted, so this is my aim for a "complete household management"-thing. ERP your fridge!
|
||||
A household needs to be managed. I did this so far (almost 10 years) with my first self written software (a C# Windows forms application) and with a bunch of Excel sheets. The software is a pain to use and Excel is Excel. So I searched for and tried different things for a (very) long time, nothing 100 % fitted, so this is my aim for a "complete household management"-thing. ERP your fridge!
|
||||
|
||||
## How to install
|
||||
> Checkout [grocy-desktop](https://github.com/grocy/grocy-desktop), if you want to run grocy without having to manage a webserver just like a normal ("indows) desktop application.
|
||||
> Checkout [grocy-desktop](https://github.com/grocy/grocy-desktop), if you want to run grocy without having to manage a webserver just like a normal (Windows) desktop application.
|
||||
>
|
||||
> Directly download the [latest release](https://releases.grocy.info/latest-desktop) - the installation is nothing more than just clicking 2 times "next".
|
||||
|
||||
@@ -38,7 +38,7 @@ grocy is technically a pretty simple PHP application, so the basic notes to get
|
||||
- Include `try_files $uri /index.php$is_args$query_string;` in your location block if you use nginx
|
||||
- Or disable URL rewriting (see the option `DISABLE_URL_REWRITING` in `data/config.php`)
|
||||
- Based on user reports, the minmimum required/working runtime is PHP 7.2 with SQLite 3.9.0
|
||||
- However, I don't really care about supporting old runtime stuff, currently everything is only tested against (means 100 % works with) PHP 7.4 with SQLite 3.27.2
|
||||
- However, I don't really care about supporting old runtime stuff, currently everything is only tested against (means 100 % works with) PHP 8.0 with SQLite 3.27.2
|
||||
- → Default login is user `admin` with password `admin`, please change the password immediately (user menu at the top right corner)
|
||||
|
||||
Alternatively clone this repository (the `release` branch always references the latest released version, or checkout the latest tagged revision) and install Composer and Yarn dependencies manually.
|
||||
@@ -65,7 +65,7 @@ _RTL languages are unfortunately not yet supported._
|
||||
|
||||
## Things worth to know
|
||||
|
||||
### REST API & data model documentation
|
||||
### REST API
|
||||
See the integrated Swagger UI instance on [/api](https://demo.grocy.info/api).
|
||||
|
||||
### Barcode readers & camera scanning
|
||||
|
20
app.php
@@ -5,6 +5,7 @@ use Grocy\Helpers\UrlManager;
|
||||
use Grocy\Middleware\CorsMiddleware;
|
||||
use Psr\Container\ContainerInterface as Container;
|
||||
use Slim\Factory\AppFactory;
|
||||
use Slim\Views\Blade;
|
||||
|
||||
// Load composer dependencies
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
@@ -14,11 +15,20 @@ require_once GROCY_DATAPATH . '/config.php';
|
||||
require_once __DIR__ . '/config-dist.php'; // For not in own config defined values we use the default ones
|
||||
require_once __DIR__ . '/helpers/ConfigurationValidator.php';
|
||||
|
||||
// Error reporting definitions
|
||||
if (GROCY_MODE === 'dev')
|
||||
{
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
else
|
||||
{
|
||||
error_reporting(E_ALL ^ (E_NOTICE | E_WARNING | E_DEPRECATED));
|
||||
}
|
||||
|
||||
// Definitions for dev/demo/prerelease mode
|
||||
if ((GROCY_MODE === 'dev' || GROCY_MODE === 'demo' || GROCY_MODE === 'prerelease') && !defined('GROCY_USER_ID'))
|
||||
{
|
||||
define('GROCY_USER_ID', 1);
|
||||
define('GROCY_SHOW_AUTH_VIEWS', true);
|
||||
}
|
||||
|
||||
// Definitions for disabled authentication mode
|
||||
@@ -28,8 +38,6 @@ if (GROCY_DISABLE_AUTH === true)
|
||||
{
|
||||
define('GROCY_USER_ID', 1);
|
||||
}
|
||||
|
||||
define('GROCY_SHOW_AUTH_VIEWS', false);
|
||||
}
|
||||
|
||||
// Check if any invalid entries in config.php have been made
|
||||
@@ -54,11 +62,13 @@ $app = AppFactory::create();
|
||||
|
||||
$container = $app->getContainer();
|
||||
$container->set('view', function (Container $container) {
|
||||
return new Slim\Views\Blade(__DIR__ . '/views', GROCY_DATAPATH . '/viewcache');
|
||||
return new Blade(__DIR__ . '/views', GROCY_DATAPATH . '/viewcache');
|
||||
});
|
||||
|
||||
$container->set('UrlManager', function (Container $container) {
|
||||
return new UrlManager(GROCY_BASE_URL);
|
||||
});
|
||||
|
||||
$container->set('ApiKeyHeaderName', function (Container $container) {
|
||||
return 'GROCY-API-KEY';
|
||||
});
|
||||
@@ -91,4 +101,6 @@ $errorMiddleware->setDefaultErrorHandler(
|
||||
);
|
||||
|
||||
$app->add(new CorsMiddleware($app->getResponseFactory()));
|
||||
|
||||
ob_clean(); // No response output before here
|
||||
$app->run();
|
||||
|
125
changelog/62_3.1.0_2021-07-16.md
Normal file
@@ -0,0 +1,125 @@
|
||||
> ⚠️ The following PHP extensions are now additionally required: `json`, `intl`, `zlib`
|
||||
|
||||
> ⚠️ PHP 8 is now supported and from now on the only tested runtime version (although currently PHP 7.2 should still work).
|
||||
|
||||
### New feature: grocycode / label printer support
|
||||
#### (Own) Product/stock entry/chores/batteries labels/barcodes
|
||||
- Print own labels/barcodes for products/stock entries/chores/batteries and then scan that code on every place a product/stock entry/chore/battery can be selected
|
||||
- Can be printed (or downloaded) via
|
||||
- The product/chore/battery edit page
|
||||
- The context/more menu per line on the overview pages and for stock entries on the stock entries page
|
||||
- Automatically on purchase (new option on the purchase page, defaults can be configured per product) for stock entries
|
||||
- The used barcode type can be configured via the `config.php` option `GROCYCODE_TYPE`:
|
||||
- `1D` (default) will produce a `Code128` 1D barcode (supported by the integrated camera barcode scanner)
|
||||
- `2D` will produce a `DataMatrix` 2D barcode (currently not supported by the integrated camera barcode scanner, but can be probably printed smaller)
|
||||
- Label printer functionality can be enabled via the new feature flag `FEATURE_FLAG_LABEL_PRINTER` (defaults to disabled)
|
||||
- Label printer communication happens via WebHooks - see the new `LABEL_PRINTER*` `config.php` options
|
||||
- grocycodes can also be used without a label printer - you can view or download thm as pictures and print them manually
|
||||
- More information:
|
||||
- https://github.com/grocy/grocy/tree/v3.1.0/docs/grocycode.md
|
||||
- https://github.com/grocy/grocy/tree/v3.1.0/docs/label-printing.md
|
||||
- (Thanks a lot @mistressofjellyfish for the initial work on this)
|
||||
|
||||
### New feature: Meal plan sections
|
||||
- Split the meal plan into sections like Breakfast/Lunch/Dinner
|
||||
- => New button "Configure sections" on the meal plan page to configure the sections (top right corner)
|
||||
- => Each meal plan entry can be assigned to a section
|
||||
|
||||
### New feature: Shopping list thermal printer support
|
||||
- The shopping list can now be printed on a thermal printer
|
||||
- The printer must be compatible to the `ESC/POS` protocol and needs to be locally attached or network reachable to/by the machine hosting grocy (so the server)
|
||||
- See the new `TPRINTER*` `config.php` options to configure the printer connection and other options
|
||||
- => New button on the shopping list print dialog
|
||||
- Can be enabled via the new feature flag `FEATURE_FLAG_THERMAL_PRINTER` (defaults to disabled)
|
||||
- (Thanks a lot @Forceu)
|
||||
|
||||
### Stock improvements/fixes
|
||||
- Product barcodes are now enforced to be unique across products
|
||||
- On the stock overview page it's now also possible to search/filter by product barcodes (via the general search field)
|
||||
- The product picker on the consume and transfer page now only shows products which are currently in stock
|
||||
- Added a filter option to only show in-stock products on the stock overview and products list (master data) page
|
||||
- Added new columns on the stock overview page (hidden by default): Product description, product default location, parent product, product picture
|
||||
- Added a new product option "Should not be frozen" (defaults to disabled and only visible when `FEATURE_FLAG_STOCK_PRODUCT_FREEZING` is enabled)
|
||||
- When enabled, on moving the product to a freezer location (so when freezing it), a corresponding warning will be shown
|
||||
- Optimized that when opening a product which has "Default due days after opened" set, the resulting date now never extends the original due date
|
||||
- Added a new stock setting (top right corner settings menu) "Add decimal separator automatically for price inputs" (defaults to disabled)
|
||||
- When enabled, you always have to enter the value including decimal places, the decimal separator will be automatically added based on the amount of allowed decimal places
|
||||
- Fixed that editing stock entries was not possible
|
||||
- Fixed that consuming with Scan Mode was not possible
|
||||
- Fixed that the current stock total value (header of the stock overview page) didn't include decimal amounts (thanks @Ape)
|
||||
- Fixed that the transfer page was not fully populated when opening it from the stock entries page
|
||||
- Fixed that undoing a consume/open action from the success notification on the stock entries page was not possible
|
||||
- Fixed that adding a barcode to a product didn't save the selected quantity unit when the product only has a single one
|
||||
- Fixed that the store information on a stock entry was lost when transferring a partial amount to a different location
|
||||
- Fixed that the "Spoil rate" on the product card was wrong in some cases
|
||||
- Fixed that the stock journal showed always the products default location (instead of the location of the transaction)
|
||||
- Fixed that the aggregated amount of parent products was wrong when indirect quantity unit conversions were used
|
||||
|
||||
### Shopping list improvements/fixes
|
||||
- The amount now defaults to `1` for adding items quicker
|
||||
- Added a status filter for only _done_ items
|
||||
- The total value is now also shown (based on "Last price (Total)" per item, displayed on the page header and only when `FEATURE_FLAG_STOCK_PRICE_TRACKING` is enabled)
|
||||
- Fixed that shopping list prints had a grey background (thanks @Forceu)
|
||||
- Fixed the form validation on the shopping list item page (thanks @Forceu)
|
||||
- Fixed that when adding products to the shopping list from the stock overview page, the used quantity unit was always the products default purchase QU (and not the selected one)
|
||||
- Fixed that the displayed last unit/total price was wrong when the used quantity unit was not the products stock QU
|
||||
- Fixed that the "Add as barcode to existing product" productpicker workflow did not work
|
||||
|
||||
### Recipe improvements/fixes
|
||||
- Recipe printing improvements (thanks @Ape)
|
||||
- Calories are now always displayed per single serving (on the recipe and meal plan page)
|
||||
- The note of an ingredient will now also be added to the corresponding shopping list item when using "Put missing products on the shopping list"
|
||||
- It's now possible to copy a recipe (button/dropdown menu item per recipe)
|
||||
- Fixed that the recipe page was slow when there were a lot meal plan recipe entries
|
||||
- Fixed that "Only check if any amount is in stock" (recipe ingredient option) didn't work for stock amounts < 1
|
||||
- Fixed that when adding missing items to the shopping list, on the popup deselected items got also added
|
||||
- Fixed that the amount of self produced products with tare weight handling enabled was wrong ("Produces product" recipe option)
|
||||
- Fixed that the ingredient amount calculation for included/nested recipes was (for most cases) wrong
|
||||
- Fixed that the ingredient amount was wrong when using a to the product indirectly related quantity unit
|
||||
- Fixed that the calories amount calculation was wrong when quantity unit conversions were involved
|
||||
|
||||
### Meal plan improvements/fixes
|
||||
- Improved the meal plan page loading time (drastically when having a big history of meal plan entries)
|
||||
- Meal plan entries can now be visually marked as "done" (new button per entry)
|
||||
- This happens automatically on consuming a recipe/product from the meal plan page
|
||||
- It's now possible to copy all entries of a day to another day (in the dropdown of the add button in the header of each day column)
|
||||
- The "Display recipe" button was removed, instead clicking the recipe title now displays the recipe (and this now also works for products; shows the product card)
|
||||
- Fixed that stock fulfillment checking used the desired servings of the recipe (those selected on the recipes page, not them from the meal plan entry)
|
||||
|
||||
### Chores improvements/fixes
|
||||
- It's now possible to track any addtional info on a chore execution by using Userfields
|
||||
- => Configure the desired Userfields for the entity `chores_log`
|
||||
- => The on chore execution tracking entered information is then visible on the corresponding chore journal entry
|
||||
- Fixed that tracking chores with "Done by" a different user was not possible
|
||||
|
||||
### Userfield improvements/fixes
|
||||
- Userfields can now be configured as mandatory (new Userfield option, defaults to disabled)
|
||||
- Fixed that numeric Userfields were initialised with `1.0`
|
||||
- Fixed that shortcuts (up/down key) and the format did not work correctly when using multiple date/time Userfields per object
|
||||
- Fixed that Userfields were not saved when adding a product or a recipe (only on editing)
|
||||
|
||||
### General & other improvements/fixes
|
||||
- LDAP authentication improvements / OpenLDAP support (thanks @tank0226)
|
||||
- A read only service account can now be used for binding
|
||||
- The username attribute is now configurable
|
||||
- Filtering of accounts is now possible
|
||||
- => See the new `LDAP*` `config.php` options
|
||||
- Improved the page loading time of all journal pages (stock/chores/batteries) by adding a new date range filter
|
||||
- Some night mode style improvements (thanks @BlizzWave and @KTibow)
|
||||
- Help tooltips are now additionally also triggered by clicking on them (instead of only hovering them, which doesn't work on mobile / touch devices)
|
||||
- The camera barcode scanner now also supports Code 39 barcodes (used for example in Germany on pharma products (PZN)) (thanks @andreheuer)
|
||||
- Fixed that the number picker up/down buttons did not work when the input field was empty or contained an invalid number
|
||||
- Fixed that links and embeds (e.g. YouTube videos) did not work in the text editor
|
||||
- Fixed that the "Manage users" and "Manage API keys" menu was not shown when using reverse proxy authentication
|
||||
|
||||
### API improvements/fixes
|
||||
> ❗ Numbers are now returned as numbers (so technically without quotes around them, were strings for nearly all endpoints before - should practically be no real difference)
|
||||
- Added a new endpoint `/system/localization-strings` to get the localization strings (gettext JSON representation; in the by the user desired language)
|
||||
- Added a new endpoint `/recipes/{recipeId}/copy` to copy a recipe
|
||||
- The `GET /chores` endpoint now also returns the `next_execution_assigned_user` object per chore (like the endpoint `GET /chores/{choreId}` already did for a single chore)
|
||||
- The `GET /tasks` endpoint now also returns the assigned user and category object per task
|
||||
- Empty Userfields are now also returned (were previously omitted, endpoint `GET /objects/{entity}` and `GET /objects/{entity}/{objectId}`)
|
||||
- Fixed that due soon products with `due_type` = "Expiration date" were missing in `due_products` of the `/stock/volatile` endpoint
|
||||
- Fixed that `PUT/DELETE /objects/{entity}/{objectId}` produced an internal server error when the given object id was invalid (now returns `400 Bad Request`)
|
||||
- Fixed that hyphens in filter values did not work
|
||||
- Fixed that cyrillic letters were not allowed in filter values
|
@@ -1,17 +1,20 @@
|
||||
{
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"php": ">=8.0",
|
||||
"slim/slim": "^4.0",
|
||||
"slim/psr7": "^1.0",
|
||||
"slim/http": "^1.0",
|
||||
"php-di/php-di": "^6.0",
|
||||
"rubellum/slim-blade-view": "^0.1.1",
|
||||
"morris/lessql": "^0.4.1",
|
||||
"berrnd/slim-blade-view": "^1.0.0",
|
||||
"morris/lessql": "^1.0",
|
||||
"gettext/gettext": "^4.8",
|
||||
"eluceo/ical": "^0.16.0",
|
||||
"eluceo/ical": "^2.2.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"gumlet/php-image-resize": "^1.9",
|
||||
"ezyang/htmlpurifier": "^4.13"
|
||||
"gumlet/php-image-resize": "^2.0",
|
||||
"ezyang/htmlpurifier": "^4.13",
|
||||
"interficieis/php-barcode": "^2.0.2",
|
||||
"guzzlehttp/guzzle": "^7.0",
|
||||
"mike42/escpos-php": "^3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
@@ -23,5 +26,8 @@
|
||||
"files": [
|
||||
"helpers/extensions.php"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"platform-check": false
|
||||
}
|
||||
}
|
||||
|
1759
composer.lock
generated
@@ -77,10 +77,13 @@ Setting('AUTH_CLASS', 'Grocy\Middleware\DefaultAuthMiddleware');
|
||||
// the name of the HTTP header which your reverse proxy uses to pass the username (on successful authentication)
|
||||
Setting('REVERSE_PROXY_AUTH_HEADER', 'REMOTE_USER');
|
||||
|
||||
// When using LdapAuthMiddleware
|
||||
Setting('LDAP_DOMAIN', ''); // Example value "local"
|
||||
// LDAP options when using LdapAuthMiddleware
|
||||
Setting('LDAP_ADDRESS', ''); // Example value "ldap://vm-dc2019.local.berrnd.net"
|
||||
Setting('LDAP_BASE_DN', ''); // Example value "OU=OU_Users,DC=local,DC=berrnd,DC=net"
|
||||
Setting('LDAP_BASE_DN', ''); // Example value "DC=local,DC=berrnd,DC=net"
|
||||
Setting('LDAP_BIND_DN', ''); // Example value "CN=grocy_bind_account,OU=service_accounts,DC=local,DC=berrnd,DC=net"
|
||||
Setting('LDAP_BIND_PW', ''); // Password for the above account
|
||||
Setting('LDAP_USER_FILTER', ''); // Example value "(OU=grocy_users)"
|
||||
Setting('LDAP_UID_ATTR', ''); // Windows AD: "sAMAccountName", OpenLDAP: "uid", GLAuth: "cn"
|
||||
|
||||
// Set this to true if you want to disable the ability to scan a barcode via the device camera (Browser API)
|
||||
Setting('DISABLE_BROWSER_BARCODE_CAMERA_SCANNING', false);
|
||||
@@ -95,6 +98,34 @@ Setting('MEAL_PLAN_FIRST_DAY_OF_WEEK', '');
|
||||
// see the file controllers/Users/User.php for possible values
|
||||
Setting('DEFAULT_PERMISSIONS', ['ADMIN']);
|
||||
|
||||
// 1D (=> Code128) or 2D (=> DataMatrix)
|
||||
Setting('GROCYCODE_TYPE', '1D');
|
||||
|
||||
// Label printer settings
|
||||
// This is the URI that grocy will POST to when asked to print a label
|
||||
Setting('LABEL_PRINTER_WEBHOOK', '');
|
||||
// This setting decides whether the webhook will be called server- or clientside
|
||||
// If the machine grocy runs on has a network connection to the host the webhook receiver is on, this is probably a good idea
|
||||
// If, for example, grocy runs in the cloud and your printer daemon runs locally to you, set this to false to let your browser call the webhook instead
|
||||
Setting('LABEL_PRINTER_RUN_SERVER', true);
|
||||
// Additional parameters supplied to the webhook
|
||||
Setting('LABEL_PRINTER_PARAMS', ['font_family' => 'Source Sans Pro (Regular)']);
|
||||
// TRUE to use JSON or FALSE to use normal POST request variables
|
||||
Setting('LABEL_PRINTER_HOOK_JSON', false);
|
||||
|
||||
// Thermal printer options
|
||||
// Thermal printers are receipt printers, not regular printers,
|
||||
// the printer must support the ESC/POS protocol, see https://github.com/mike42/escpos-php
|
||||
Setting('TPRINTER_IS_NETWORK_PRINTER', false); // Set to true if it's' a network printer
|
||||
Setting('TPRINTER_PRINT_QUANTITY_NAME', true); // Set to false if you do not want to print the quantity names (related to the shopping list)
|
||||
Setting('TPRINTER_PRINT_NOTES', true); // Set to false if you do not want to print notes (related to the shopping list)
|
||||
Setting('TPRINTER_IP', '127.0.0.1'); // IP of the network printer (does only matter if it's a network printer)
|
||||
Setting('TPRINTER_PORT', 9100); // Port of the network printer
|
||||
Setting('TPRINTER_CONNECTOR', '/dev/usb/lp0'); // Printer device (does only matter if you use a locally attached printer)
|
||||
// For USB on Linux this is often '/dev/usb/lp0', for serial printers it could be similar to '/dev/ttyS0'
|
||||
// Make sure that the user that runs the webserver has permissions to write to the printer - on Linux add your webserver user to the LP group with usermod -a -G lp www-data
|
||||
|
||||
|
||||
// Default user settings
|
||||
// These settings can be changed per user, here the defaults
|
||||
// are defined which are used when the user has not changed the setting so far
|
||||
@@ -117,6 +148,7 @@ DefaultUserSetting('product_presets_product_group_id', -1); // Default product g
|
||||
DefaultUserSetting('product_presets_qu_id', -1); // Default quantity unit id for new products (-1 means no quantity unit is preset)
|
||||
DefaultUserSetting('stock_decimal_places_amounts', 4); // Default decimal places allowed for amounts
|
||||
DefaultUserSetting('stock_decimal_places_prices', 2); // Default decimal places allowed for prices
|
||||
DefaultUserSetting('stock_auto_decimal_separator_prices', false);
|
||||
DefaultUserSetting('stock_due_soon_days', 5);
|
||||
DefaultUserSetting('stock_default_purchase_amount', 0);
|
||||
DefaultUserSetting('stock_default_consume_amount', 1);
|
||||
@@ -124,7 +156,7 @@ DefaultUserSetting('stock_default_consume_amount_use_quick_consume_amount', fals
|
||||
DefaultUserSetting('scan_mode_consume_enabled', false);
|
||||
DefaultUserSetting('scan_mode_purchase_enabled', false);
|
||||
DefaultUserSetting('show_icon_on_stock_overview_page_when_product_is_on_shopping_list', true);
|
||||
DefaultUserSetting('show_purchased_date_on_purchase', false); // Wheter the purchased date should be editable on purchase (defaults to today otherwise)
|
||||
DefaultUserSetting('show_purchased_date_on_purchase', false); // Whether the purchased date should be editable on purchase (defaults to today otherwise)
|
||||
DefaultUserSetting('show_warning_on_purchase_when_due_date_is_earlier_than_next', true); // Show a warning on purchase when the due date of the purchased product is earlier than the next due date in stock
|
||||
|
||||
// Shopping list settings
|
||||
@@ -143,9 +175,8 @@ DefaultUserSetting('batteries_due_soon_days', 5);
|
||||
// Tasks settings
|
||||
DefaultUserSetting('tasks_due_soon_days', 5);
|
||||
|
||||
// If the page should be automatically reloaded when there was
|
||||
// an external change
|
||||
DefaultUserSetting('auto_reload_on_db_change', true);
|
||||
// If the page should be automatically reloaded when there was an external change
|
||||
DefaultUserSetting('auto_reload_on_db_change', false);
|
||||
|
||||
// Show a clock in the header next to the logo or not
|
||||
DefaultUserSetting('show_clock_in_header', false);
|
||||
@@ -159,6 +190,7 @@ DefaultUserSetting('quagga2_patchsize', 'medium');
|
||||
DefaultUserSetting('quagga2_frequency', 10);
|
||||
DefaultUserSetting('quagga2_debug', true);
|
||||
|
||||
|
||||
// Feature flags
|
||||
// grocy was initially about "stock management for your household", many other things
|
||||
// came and still come by, because they are useful - here you can disable the parts
|
||||
@@ -172,6 +204,7 @@ Setting('FEATURE_FLAG_TASKS', true);
|
||||
Setting('FEATURE_FLAG_BATTERIES', true);
|
||||
Setting('FEATURE_FLAG_EQUIPMENT', true);
|
||||
Setting('FEATURE_FLAG_CALENDAR', true);
|
||||
Setting('FEATURE_FLAG_LABEL_PRINTER', false);
|
||||
|
||||
// Sub feature flags
|
||||
Setting('FEATURE_FLAG_STOCK_PRICE_TRACKING', true);
|
||||
@@ -182,7 +215,8 @@ Setting('FEATURE_FLAG_STOCK_PRODUCT_FREEZING', true);
|
||||
Setting('FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_FIELD_NUMBER_PAD', true); // Activate the number pad in due date fields on (supported) mobile browsers
|
||||
Setting('FEATURE_FLAG_SHOPPINGLIST_MULTIPLE_LISTS', true);
|
||||
Setting('FEATURE_FLAG_CHORES_ASSIGNMENTS', true);
|
||||
Setting('FEATURE_FLAG_THERMAL_PRINTER', false);
|
||||
|
||||
// Feature settings
|
||||
Setting('FEATURE_SETTING_STOCK_COUNT_OPENED_PRODUCTS_AGAINST_MINIMUM_STOCK_AMOUNT', true); // When set to true, opened items will be counted as missing for calculating if a product is below its minimum stock amount
|
||||
Setting('FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA', true); // Enables the torch automaticaly (if the device has one)
|
||||
Setting('FEATURE_FLAG_AUTO_TORCH_ON_WITH_CAMERA', true); // Enables the torch automatically (if the device has one)
|
||||
|
@@ -6,20 +6,22 @@ use LessQL\Result;
|
||||
|
||||
class BaseApiController extends BaseController
|
||||
{
|
||||
const PATTERN_FIELD = '[A-Za-z_][A-Za-z0-9_]+';
|
||||
|
||||
const PATTERN_OPERATOR = '!?(=|~|<|>|(>=)|(<=)|(§))';
|
||||
|
||||
const PATTERN_VALUE = '[A-Za-z\x{0400}-\x{04FF}_0-9.$#^|-]+';
|
||||
|
||||
protected $OpenApiSpec = null;
|
||||
|
||||
const PATTERN_FIELD = '[A-Za-z_][A-Za-z0-9_]+';
|
||||
const PATTERN_OPERATOR = '!?(=|~|<|>|(>=)|(<=)|(§))';
|
||||
const PATTERN_VALUE = '[A-Za-z_0-9.$#^|]+';
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
protected function ApiResponse(\Psr\Http\Message\ResponseInterface $response, $data, $cache = false)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
if ($cache)
|
||||
{
|
||||
$response = $response->withHeader('Cache-Control', 'max-age=2592000');
|
||||
}
|
||||
|
||||
protected function ApiResponse(\Psr\Http\Message\ResponseInterface $response, $data)
|
||||
{
|
||||
$response->getBody()->write(json_encode($data));
|
||||
$response->getBody()->write(json_encode($data, JSON_NUMERIC_CHECK));
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -83,7 +85,7 @@ class BaseApiController extends BaseController
|
||||
preg_match(
|
||||
'/(?P<field>' . self::PATTERN_FIELD . ')'
|
||||
. '(?P<op>' . self::PATTERN_OPERATOR . ')'
|
||||
. '(?P<value>' . self::PATTERN_VALUE . ')/',
|
||||
. '(?P<value>' . self::PATTERN_VALUE . ')/u',
|
||||
$q,
|
||||
$matches
|
||||
);
|
||||
|
@@ -11,6 +11,7 @@ use Grocy\Services\ChoresService;
|
||||
use Grocy\Services\DatabaseService;
|
||||
use Grocy\Services\FilesService;
|
||||
use Grocy\Services\LocalizationService;
|
||||
use Grocy\Services\PrintService;
|
||||
use Grocy\Services\RecipesService;
|
||||
use Grocy\Services\SessionService;
|
||||
use Grocy\Services\StockService;
|
||||
@@ -20,14 +21,14 @@ use Grocy\Services\UsersService;
|
||||
|
||||
class BaseController
|
||||
{
|
||||
protected $AppContainer;
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
$this->AppContainer = $container;
|
||||
$this->View = $container->get('view');
|
||||
}
|
||||
|
||||
protected $AppContainer;
|
||||
|
||||
protected function getApiKeyService()
|
||||
{
|
||||
return ApiKeyService::getInstance();
|
||||
@@ -93,6 +94,11 @@ class BaseController
|
||||
return StockService::getInstance();
|
||||
}
|
||||
|
||||
protected function getPrintService()
|
||||
{
|
||||
return PrintService::getInstance();
|
||||
}
|
||||
|
||||
protected function getTasksService()
|
||||
{
|
||||
return TasksService::getInstance();
|
||||
@@ -123,7 +129,7 @@ class BaseController
|
||||
$this->View->set('__n', function ($number, $singularForm, $pluralForm) use ($localizationService) {
|
||||
return $localizationService->__n($number, $singularForm, $pluralForm);
|
||||
});
|
||||
$this->View->set('GettextPo', $localizationService->GetPoAsJsonString());
|
||||
$this->View->set('LocalizationStrings', $localizationService->GetPoAsJsonString());
|
||||
|
||||
// TODO: Better handle this generically based on the current language (header in .po file?)
|
||||
$dir = 'ltr';
|
||||
@@ -157,18 +163,18 @@ class BaseController
|
||||
if (GROCY_AUTHENTICATED)
|
||||
{
|
||||
$this->View->set('permissions', User::PermissionList());
|
||||
}
|
||||
|
||||
$decimalPlacesAmounts = intval($this->getUsersService()->GetUserSetting(GROCY_USER_ID, 'stock_decimal_places_amounts'));
|
||||
if ($decimalPlacesAmounts <= 0)
|
||||
{
|
||||
$defaultMinAmount = 1;
|
||||
$decimalPlacesAmounts = intval($this->getUsersService()->GetUserSetting(GROCY_USER_ID, 'stock_decimal_places_amounts'));
|
||||
if ($decimalPlacesAmounts <= 0)
|
||||
{
|
||||
$defaultMinAmount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$defaultMinAmount = '0.' . str_repeat('0', $decimalPlacesAmounts - 1) . '1';
|
||||
}
|
||||
$this->View->set('DEFAULT_MIN_AMOUNT', $defaultMinAmount);
|
||||
}
|
||||
else
|
||||
{
|
||||
$defaultMinAmount = '0.' . str_repeat('0', $decimalPlacesAmounts - 1) . '1';
|
||||
}
|
||||
$this->View->set('DEFAULT_MIN_AMOUNT', $defaultMinAmount);
|
||||
|
||||
return $this->View->render($response, $page, $data);
|
||||
}
|
||||
@@ -203,9 +209,13 @@ class BaseController
|
||||
if (self::$htmlPurifierInstance == null)
|
||||
{
|
||||
$htmlPurifierConfig = \HTMLPurifier_Config::createDefault();
|
||||
$htmlPurifierConfig->set('HTML.Allowed', 'div,b,strong,i,em,u,a[href|title],ul,ol,li,p[style],br,span[style],img[width|height|alt|src],table[border|width|style],tbody,tr,td,th,blockquote');
|
||||
$htmlPurifierConfig->set('Cache.SerializerPath', GROCY_DATAPATH . '/viewcache');
|
||||
$htmlPurifierConfig->set('HTML.Allowed', 'div,b,strong,i,em,u,a[href|title|target],iframe[src|width|height|frameborder],ul,ol,li,p[style],br,span[style],img[width|height|alt|src],table[border|width|style],tbody,tr,td,th,blockquote,*[style|class|id]');
|
||||
$htmlPurifierConfig->set('Attr.EnableID', true);
|
||||
$htmlPurifierConfig->set('HTML.SafeIframe', true);
|
||||
$htmlPurifierConfig->set('CSS.AllowedProperties', 'font,font-size,font-weight,font-style,font-family,text-decoration,padding-left,color,background-color,text-align');
|
||||
$htmlPurifierConfig->set('URI.AllowedSchemes', ['data' => true]);
|
||||
$htmlPurifierConfig->set('URI.AllowedSchemes', ['data' => true, 'http' => true, 'https' => true]);
|
||||
$htmlPurifierConfig->set('URI.SafeIframeRegexp', '%^.*%'); // Allow any iframe source
|
||||
|
||||
self::$htmlPurifierInstance = new \HTMLPurifier($htmlPurifierConfig);
|
||||
}
|
||||
@@ -213,15 +223,18 @@ class BaseController
|
||||
$requestBody = $request->getParsedBody();
|
||||
foreach ($requestBody as $key => &$value)
|
||||
{
|
||||
// HTMLPurifier removes boolean values (true/false), so explicitly keep them
|
||||
// HTMLPurifier removes boolean values (true/false) and arrays, so explicitly keep them
|
||||
// Maybe also possible through HTMLPurifier config (http://htmlpurifier.org/live/configdoc/plain.html)
|
||||
if (!is_bool($value))
|
||||
if (!is_bool($value) && !is_array($value))
|
||||
{
|
||||
$value = self::$htmlPurifierInstance->purify($value);
|
||||
}
|
||||
|
||||
// Allow some special chars
|
||||
$value = str_replace('&', '&', $value);
|
||||
if (!is_array($value))
|
||||
{
|
||||
$value = str_replace('&', '&', $value);
|
||||
}
|
||||
}
|
||||
|
||||
return $requestBody;
|
||||
|
@@ -3,6 +3,8 @@
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
use Grocy\Helpers\WebhookRunner;
|
||||
use Grocy\Helpers\Grocycode;
|
||||
|
||||
class BatteriesApiController extends BaseApiController
|
||||
{
|
||||
@@ -32,7 +34,6 @@ class BatteriesApiController extends BaseApiController
|
||||
try
|
||||
{
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
|
||||
if (array_key_exists('tracked_time', $requestBody) && IsIsoDateTime($requestBody['tracked_time']))
|
||||
{
|
||||
$trackedTime = $requestBody['tracked_time'];
|
||||
@@ -62,8 +63,27 @@ class BatteriesApiController extends BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
public function BatteryPrintLabel(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
parent::__construct($container);
|
||||
try
|
||||
{
|
||||
$battery = $this->getDatabase()->batteries()->where('id', $args['batteryId'])->fetch();
|
||||
|
||||
$webhookData = array_merge([
|
||||
'battery' => $battery->name,
|
||||
'grocycode' => (string)(new Grocycode(Grocycode::BATTERY, $args['batteryId'])),
|
||||
], GROCY_LABEL_PRINTER_PARAMS);
|
||||
|
||||
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
||||
{
|
||||
(new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON);
|
||||
}
|
||||
|
||||
return $this->ApiResponse($response, $webhookData);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,8 +2,12 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Helpers\Grocycode;
|
||||
|
||||
class BatteriesController extends BaseController
|
||||
{
|
||||
use GrocycodeTrait;
|
||||
|
||||
public function BatteriesList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if (isset($request->getQueryParams()['include_disabled']))
|
||||
@@ -48,8 +52,25 @@ class BatteriesController extends BaseController
|
||||
|
||||
public function Journal(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if (isset($request->getQueryParams()['months']) && filter_var($request->getQueryParams()['months'], FILTER_VALIDATE_INT) !== false)
|
||||
{
|
||||
$months = $request->getQueryParams()['months'];
|
||||
$where = "tracked_time > DATE(DATE('now', 'localtime'), '-$months months')";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default 2 years
|
||||
$where = "tracked_time > DATE(DATE('now', 'localtime'), '-24 months')";
|
||||
}
|
||||
|
||||
if (isset($request->getQueryParams()['battery']) && filter_var($request->getQueryParams()['battery'], FILTER_VALIDATE_INT) !== false)
|
||||
{
|
||||
$batteryId = $request->getQueryParams()['battery'];
|
||||
$where .= " AND battery_id = $batteryId";
|
||||
}
|
||||
|
||||
return $this->renderPage($response, 'batteriesjournal', [
|
||||
'chargeCycles' => $this->getDatabase()->battery_charge_cycles()->orderBy('tracked_time', 'DESC'),
|
||||
'chargeCycles' => $this->getDatabase()->battery_charge_cycles()->where($where)->orderBy('tracked_time', 'DESC'),
|
||||
'batteries' => $this->getDatabase()->batteries()->where('active = 1')->orderBy('name', 'COLLATE NOCASE')
|
||||
]);
|
||||
}
|
||||
@@ -75,8 +96,9 @@ class BatteriesController extends BaseController
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
public function BatteryGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$gc = new Grocycode(Grocycode::BATTERY, $args['batteryId']);
|
||||
return $this->ServeGrocycodeImage($request, $response, $gc);
|
||||
}
|
||||
}
|
||||
|
@@ -2,44 +2,54 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Eluceo\iCal\Domain\Entity\Calendar;
|
||||
use Eluceo\iCal\Domain\Entity\Event;
|
||||
use Eluceo\iCal\Domain\ValueObject\Date;
|
||||
use Eluceo\iCal\Domain\ValueObject\DateTime;
|
||||
use Eluceo\iCal\Domain\ValueObject\SingleDay;
|
||||
use Eluceo\iCal\Domain\ValueObject\TimeSpan;
|
||||
use Eluceo\iCal\Presentation\Factory\CalendarFactory;
|
||||
|
||||
class CalendarApiController extends BaseApiController
|
||||
{
|
||||
public function Ical(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$vCalendar = new \Eluceo\iCal\Component\Calendar('grocy');
|
||||
|
||||
$events = $this->getCalendarService()->GetEvents();
|
||||
|
||||
$vCalendar = new Calendar();
|
||||
foreach ($events as $event)
|
||||
{
|
||||
$date = new \DateTime($event['start']);
|
||||
$date->setTimezone(new \DateTimeZone(date_default_timezone_get()));
|
||||
|
||||
if ($event['date_format'] === 'date')
|
||||
{
|
||||
$date->setTime(23, 59, 59);
|
||||
}
|
||||
|
||||
$description = '';
|
||||
if (isset($event['description']))
|
||||
{
|
||||
$description = $event['description'];
|
||||
}
|
||||
|
||||
$vEvent = new \Eluceo\iCal\Component\Event();
|
||||
$vEvent->setDtStart($date)
|
||||
->setDtEnd($date)
|
||||
->setSummary($event['title'])
|
||||
->setDescription($description)
|
||||
->setNoTime($event['date_format'] === 'date' || (isset($event['allDay']) && $event['allDay']))
|
||||
->setUseTimezone(true);
|
||||
if ($event['date_format'] === 'date' || (isset($event['allDay']) && $event['allDay']))
|
||||
{
|
||||
// All-day event
|
||||
$date = new Date(\DateTimeImmutable::createFromFormat('Y-m-d', $event['start']));
|
||||
$vEventOccurrence = new SingleDay($date);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Time-point event
|
||||
$start = new DateTime(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $event['start']), false);
|
||||
$end = new DateTime(\DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $event['start']), false);
|
||||
$vEventOccurrence = new TimeSpan($start, $end);
|
||||
}
|
||||
|
||||
$vCalendar->addComponent($vEvent);
|
||||
$vEvent = new Event();
|
||||
$vEvent->setOccurrence($vEventOccurrence)
|
||||
->setSummary($event['title'])
|
||||
->setDescription($description);
|
||||
|
||||
$vCalendar->addEvent($vEvent);
|
||||
}
|
||||
|
||||
$response->write($vCalendar->render());
|
||||
$response->write((new CalendarFactory())->createCalendar($vCalendar));
|
||||
$response = $response->withHeader('Content-Type', 'text/calendar; charset=utf-8');
|
||||
return $response->withHeader('Content-Disposition', 'attachment; filename="grocy.ics"');
|
||||
}
|
||||
@@ -62,9 +72,4 @@ class CalendarApiController extends BaseApiController
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
@@ -10,9 +10,4 @@ class CalendarController extends BaseController
|
||||
'fullcalendarEventSources' => $this->getCalendarService()->GetEvents()
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,8 @@
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
use Grocy\Helpers\WebhookRunner;
|
||||
use Grocy\Helpers\Grocycode;
|
||||
|
||||
class ChoresApiController extends BaseApiController
|
||||
{
|
||||
@@ -66,14 +68,12 @@ class ChoresApiController extends BaseApiController
|
||||
User::checkPermission($request, User::PERMISSION_CHORE_TRACK_EXECUTION);
|
||||
|
||||
$trackedTime = date('Y-m-d H:i:s');
|
||||
|
||||
if (array_key_exists('tracked_time', $requestBody) && (IsIsoDateTime($requestBody['tracked_time']) || IsIsoDate($requestBody['tracked_time'])))
|
||||
{
|
||||
$trackedTime = $requestBody['tracked_time'];
|
||||
}
|
||||
|
||||
$doneBy = GROCY_USER_ID;
|
||||
|
||||
if (array_key_exists('done_by', $requestBody) && !empty($requestBody['done_by']))
|
||||
{
|
||||
$doneBy = $requestBody['done_by'];
|
||||
@@ -81,7 +81,7 @@ class ChoresApiController extends BaseApiController
|
||||
|
||||
if ($doneBy != GROCY_USER_ID)
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_CHORE_TRACK_EXECUTION_EXECUTION);
|
||||
User::checkPermission($request, User::PERMISSION_CHORE_TRACK_EXECUTION);
|
||||
}
|
||||
|
||||
$choreExecutionId = $this->getChoresService()->TrackChore($args['choreId'], $trackedTime, $doneBy);
|
||||
@@ -108,8 +108,27 @@ class ChoresApiController extends BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
public function ChorePrintLabel(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
parent::__construct($container);
|
||||
try
|
||||
{
|
||||
$chore = $this->getDatabase()->chores()->where('id', $args['choreId'])->fetch();
|
||||
|
||||
$webhookData = array_merge([
|
||||
'chore' => $chore->name,
|
||||
'grocycode' => (string)(new Grocycode(Grocycode::CHORE, $args['choreId'])),
|
||||
], GROCY_LABEL_PRINTER_PARAMS);
|
||||
|
||||
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
||||
{
|
||||
(new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON);
|
||||
}
|
||||
|
||||
return $this->ApiResponse($response, $webhookData);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,8 +2,12 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Helpers\Grocycode;
|
||||
|
||||
class ChoresController extends BaseController
|
||||
{
|
||||
use GrocycodeTrait;
|
||||
|
||||
public function ChoreEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$usersService = $this->getUsersService();
|
||||
@@ -59,10 +63,29 @@ class ChoresController extends BaseController
|
||||
|
||||
public function Journal(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if (isset($request->getQueryParams()['months']) && filter_var($request->getQueryParams()['months'], FILTER_VALIDATE_INT) !== false)
|
||||
{
|
||||
$months = $request->getQueryParams()['months'];
|
||||
$where = "tracked_time > DATE(DATE('now', 'localtime'), '-$months months')";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default 1 year
|
||||
$where = "tracked_time > DATE(DATE('now', 'localtime'), '-12 months')";
|
||||
}
|
||||
|
||||
if (isset($request->getQueryParams()['chore']) && filter_var($request->getQueryParams()['chore'], FILTER_VALIDATE_INT) !== false)
|
||||
{
|
||||
$choreId = $request->getQueryParams()['chore'];
|
||||
$where .= " AND chore_id = $choreId";
|
||||
}
|
||||
|
||||
return $this->renderPage($response, 'choresjournal', [
|
||||
'choresLog' => $this->getDatabase()->chores_log()->orderBy('tracked_time', 'DESC'),
|
||||
'choresLog' => $this->getDatabase()->chores_log()->where($where)->orderBy('tracked_time', 'DESC'),
|
||||
'chores' => $this->getDatabase()->chores()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'users' => $this->getDatabase()->users()->orderBy('username')
|
||||
'users' => $this->getDatabase()->users()->orderBy('username'),
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('chores_log'),
|
||||
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('chores_log')
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -85,12 +108,14 @@ class ChoresController extends BaseController
|
||||
{
|
||||
return $this->renderPage($response, 'choretracking', [
|
||||
'chores' => $this->getDatabase()->chores()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'users' => $this->getDatabase()->users()->orderBy('username')
|
||||
'users' => $this->getDatabase()->users()->orderBy('username'),
|
||||
'userfields' => $this->getUserfieldsService()->GetFields('chores_log'),
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
public function ChoreGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$gc = new Grocycode(Grocycode::CHORE, $args['choreId']);
|
||||
return $this->ServeGrocycodeImage($request, $response, $gc);
|
||||
}
|
||||
}
|
||||
|
@@ -33,9 +33,4 @@ class EquipmentController extends BaseController
|
||||
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('equipment')
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
@@ -11,17 +11,17 @@ use Throwable;
|
||||
|
||||
class ExceptionController extends BaseApiController
|
||||
{
|
||||
/**
|
||||
* @var \Slim\App
|
||||
*/
|
||||
private $app;
|
||||
|
||||
public function __construct(\Slim\App $app, \DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
$this->app = $app;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \Slim\App
|
||||
*/
|
||||
private $app;
|
||||
|
||||
public function __invoke(ServerRequestInterface $request, Throwable $exception, bool $displayErrorDetails, bool $logErrors, bool $logErrorDetails, ?LoggerInterface $logger = null)
|
||||
{
|
||||
$response = $this->app->getResponseFactory()->createResponse();
|
||||
@@ -59,7 +59,10 @@ class ExceptionController extends BaseApiController
|
||||
|
||||
if ($exception instanceof HttpNotFoundException)
|
||||
{
|
||||
define('GROCY_AUTHENTICATED', false);
|
||||
if (!defined('GROCY_AUTHENTICATED'))
|
||||
{
|
||||
define('GROCY_AUTHENTICATED', false);
|
||||
}
|
||||
|
||||
return $this->renderPage($response->withStatus(404), 'errors/404', [
|
||||
'exception' => $exception
|
||||
|
@@ -11,6 +11,11 @@ class FilesApiController extends BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!in_array($args['group'], $this->getOpenApiSpec()->components->schemas->FileGroups->enum))
|
||||
{
|
||||
throw new \Exception('Invalid file group');
|
||||
}
|
||||
|
||||
if (IsValidFileName(base64_decode($args['fileName'])))
|
||||
{
|
||||
$fileName = base64_decode($args['fileName']);
|
||||
@@ -20,12 +25,7 @@ class FilesApiController extends BaseApiController
|
||||
throw new \Exception('Invalid filename');
|
||||
}
|
||||
|
||||
$filePath = $this->getFilesService()->GetFilePath($args['group'], $fileName);
|
||||
|
||||
if (file_exists($filePath))
|
||||
{
|
||||
unlink($filePath);
|
||||
}
|
||||
$this->getFilesService()->DeleteFile($args['group'], $fileName);
|
||||
|
||||
return $this->EmptyApiResponse($response);
|
||||
}
|
||||
@@ -39,8 +39,12 @@ class FilesApiController extends BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
$fileName = $this->checkFileName($args['fileName']);
|
||||
if (!in_array($args['group'], $this->getOpenApiSpec()->components->schemas->FileGroups->enum))
|
||||
{
|
||||
throw new \Exception('Invalid file group');
|
||||
}
|
||||
|
||||
$fileName = $this->checkFileName($args['fileName']);
|
||||
$filePath = $this->getFilePath($args['group'], $fileName, $request->getQueryParams());
|
||||
|
||||
if (file_exists($filePath))
|
||||
@@ -65,9 +69,13 @@ class FilesApiController extends BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!in_array($args['group'], $this->getOpenApiSpec()->components->schemas->FileGroups->enum))
|
||||
{
|
||||
throw new \Exception('Invalid file group');
|
||||
}
|
||||
|
||||
$fileInfo = explode('_', $args['fileName']);
|
||||
$fileName = $this->checkFileName($fileInfo[1]);
|
||||
|
||||
$filePath = $this->getFilePath($args['group'], base64_decode($fileInfo[0]), $request->getQueryParams());
|
||||
|
||||
if (file_exists($filePath))
|
||||
@@ -92,9 +100,14 @@ class FilesApiController extends BaseApiController
|
||||
{
|
||||
try
|
||||
{
|
||||
$fileName = $this->checkFileName($args['fileName']);
|
||||
if (!in_array($args['group'], $this->getOpenApiSpec()->components->schemas->FileGroups->enum))
|
||||
{
|
||||
throw new \Exception('Invalid file group');
|
||||
}
|
||||
|
||||
$fileName = $this->checkFileName($args['fileName']);
|
||||
$data = $request->getBody()->getContents();
|
||||
|
||||
file_put_contents($this->getFilesService()->GetFilePath($args['group'], $fileName), $data);
|
||||
|
||||
return $this->EmptyApiResponse($response);
|
||||
@@ -105,11 +118,6 @@ class FilesApiController extends BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $fileName base64-encoded file-name
|
||||
* @return false|string the decoded file-name
|
||||
@@ -138,7 +146,6 @@ class FilesApiController extends BaseApiController
|
||||
protected function getFilePath(string $group, string $fileName, array $queryParams = [])
|
||||
{
|
||||
$forceServeAs = null;
|
||||
|
||||
if (isset($queryParams['force_serve_as']) && !empty($queryParams['force_serve_as']))
|
||||
{
|
||||
$forceServeAs = $queryParams['force_serve_as'];
|
||||
@@ -147,14 +154,12 @@ class FilesApiController extends BaseApiController
|
||||
if ($forceServeAs == FilesService::FILE_SERVE_TYPE_PICTURE)
|
||||
{
|
||||
$bestFitHeight = null;
|
||||
|
||||
if (isset($queryParams['best_fit_height']) && !empty($queryParams['best_fit_height']) && is_numeric($queryParams['best_fit_height']))
|
||||
{
|
||||
$bestFitHeight = $queryParams['best_fit_height'];
|
||||
}
|
||||
|
||||
$bestFitWidth = null;
|
||||
|
||||
if (isset($queryParams['best_fit_width']) && !empty($queryParams['best_fit_width']) && is_numeric($queryParams['best_fit_width']))
|
||||
{
|
||||
$bestFitWidth = $queryParams['best_fit_width'];
|
||||
|
@@ -58,6 +58,11 @@ class GenericEntityApiController extends BaseApiController
|
||||
}
|
||||
|
||||
$row = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
||||
if ($row == null)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, 'Object not found', 400);
|
||||
}
|
||||
|
||||
$row->delete();
|
||||
$success = $row->isClean();
|
||||
|
||||
@@ -90,6 +95,11 @@ class GenericEntityApiController extends BaseApiController
|
||||
}
|
||||
|
||||
$row = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
||||
if ($row == null)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, 'Object not found', 400);
|
||||
}
|
||||
|
||||
$row->update($requestBody);
|
||||
$success = $row->isClean();
|
||||
|
||||
@@ -111,14 +121,12 @@ class GenericEntityApiController extends BaseApiController
|
||||
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoListing($args['entity']))
|
||||
{
|
||||
$userfields = $this->getUserfieldsService()->GetValues($args['entity'], $args['objectId']);
|
||||
|
||||
if (count($userfields) === 0)
|
||||
{
|
||||
$userfields = null;
|
||||
}
|
||||
|
||||
$object = $this->getDatabase()->{$args['entity']}($args['objectId']);
|
||||
|
||||
if ($object == null)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, 'Object not found', 404);
|
||||
@@ -136,33 +144,39 @@ class GenericEntityApiController extends BaseApiController
|
||||
|
||||
public function GetObjects(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$objects = $this->queryData($this->getDatabase()->{$args['entity']}(), $request->getQueryParams());
|
||||
$allUserfields = $this->getUserfieldsService()->GetAllValues($args['entity']);
|
||||
|
||||
foreach ($objects as $object)
|
||||
{
|
||||
$userfields = FindAllObjectsInArrayByPropertyValue($allUserfields, 'object_id', $object->id);
|
||||
$userfieldKeyValuePairs = null;
|
||||
|
||||
if (count($userfields) > 0)
|
||||
{
|
||||
foreach ($userfields as $userfield)
|
||||
{
|
||||
$userfieldKeyValuePairs[$userfield->name] = $userfield->value;
|
||||
}
|
||||
}
|
||||
|
||||
$object->userfields = $userfieldKeyValuePairs;
|
||||
}
|
||||
|
||||
if ($this->IsValidExposedEntity($args['entity']) && !$this->IsEntityWithNoListing($args['entity']))
|
||||
{
|
||||
return $this->ApiResponse($response, $objects);
|
||||
}
|
||||
else
|
||||
if (!$this->IsValidExposedEntity($args['entity']) || $this->IsEntityWithNoListing($args['entity']))
|
||||
{
|
||||
return $this->GenericErrorResponse($response, 'Entity does not exist or is not exposed');
|
||||
}
|
||||
|
||||
$objects = $this->queryData($this->getDatabase()->{$args['entity']}(), $request->getQueryParams());
|
||||
$userfields = $this->getUserfieldsService()->GetFields($args['entity']);
|
||||
|
||||
if (count($userfields) > 0)
|
||||
{
|
||||
$allUserfieldValues = $this->getUserfieldsService()->GetAllValues($args['entity']);
|
||||
|
||||
foreach ($objects as $object)
|
||||
{
|
||||
$userfieldKeyValuePairs = null;
|
||||
foreach ($userfields as $userfield)
|
||||
{
|
||||
$value = FindObjectInArrayByPropertyValue($allUserfieldValues, 'object_id', $object->id);
|
||||
if ($value)
|
||||
{
|
||||
$userfieldKeyValuePairs[$userfield->name] = $value->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$userfieldKeyValuePairs[$userfield->name] = null;
|
||||
}
|
||||
}
|
||||
|
||||
$object->userfields = $userfieldKeyValuePairs;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->ApiResponse($response, $objects);
|
||||
}
|
||||
|
||||
public function GetUserfields(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
@@ -199,33 +213,28 @@ class GenericEntityApiController extends BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
private function IsEntityWithEditRequiresAdmin($entity)
|
||||
{
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->internalSchemas->ExposedEntityEditRequiresAdmin->enum);
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntityEditRequiresAdmin->enum);
|
||||
}
|
||||
|
||||
private function IsEntityWithNoListing($entity)
|
||||
{
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->internalSchemas->ExposedEntityNoListing->enum);
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntityNoListing->enum);
|
||||
}
|
||||
|
||||
private function IsEntityWithNoEdit($entity)
|
||||
{
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->internalSchemas->ExposedEntityNoEdit->enum);
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntityNoEdit->enum);
|
||||
}
|
||||
|
||||
private function IsEntityWithNoDelete($entity)
|
||||
{
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->internalSchemas->ExposedEntityNoDelete->enum);
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntityNoDelete->enum);
|
||||
}
|
||||
|
||||
private function IsValidExposedEntity($entity)
|
||||
{
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->internalSchemas->ExposedEntity->enum);
|
||||
return in_array($entity, $this->getOpenApiSpec()->components->schemas->ExposedEntity->enum);
|
||||
}
|
||||
}
|
||||
|
@@ -91,9 +91,4 @@ class GenericEntityController extends BaseController
|
||||
'userfieldValues' => $this->getUserfieldsService()->GetAllValues('userentity-' . $args['userentityName'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
45
controllers/GrocycodeTrait.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Helpers\Grocycode;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use jucksearm\barcode\lib\BarcodeFactory;
|
||||
use jucksearm\barcode\lib\DatamatrixFactory;
|
||||
|
||||
trait GrocycodeTrait
|
||||
{
|
||||
public function ServeGrocycodeImage(ServerRequestInterface $request, ResponseInterface $response, Grocycode $grocycode)
|
||||
{
|
||||
$size = $request->getQueryParam('size', null);
|
||||
|
||||
if (GROCY_GROCYCODE_TYPE == '2D')
|
||||
{
|
||||
$png = (new DatamatrixFactory())->setCode((string) $grocycode)->setSize($size)->getDatamatrixPngData();
|
||||
}
|
||||
else
|
||||
{
|
||||
$png = (new BarcodeFactory())->setType('C128')->setCode((string) $grocycode)->setHeight($size)->getBarcodePngData();
|
||||
}
|
||||
|
||||
$isDownload = $request->getQueryParam('download', false);
|
||||
if ($isDownload)
|
||||
{
|
||||
$response = $response->withHeader('Content-Type', 'application/octet-stream')
|
||||
->withHeader('Content-Disposition', 'attachment; filename=grocycode.png')
|
||||
->withHeader('Content-Length', strlen($png))
|
||||
->withHeader('Cache-Control', 'no-cache')
|
||||
->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
}
|
||||
else
|
||||
{
|
||||
$response = $response->withHeader('Content-Type', 'image/png')
|
||||
->withHeader('Content-Length', strlen($png))
|
||||
->withHeader('Cache-Control', 'no-cache')
|
||||
->withHeader('Last-Modified', gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
}
|
||||
$response->getBody()->write($png);
|
||||
return $response;
|
||||
}
|
||||
}
|
@@ -6,11 +6,6 @@ use Grocy\Services\SessionService;
|
||||
|
||||
class LoginController extends BaseController
|
||||
{
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
public function LoginPage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
return $this->renderPage($response, 'login');
|
||||
|
@@ -36,30 +36,45 @@ class OpenApiController extends BaseApiController
|
||||
$spec->info->description = str_replace('PlaceHolderManageApiKeysUrl', $this->AppContainer->get('UrlManager')->ConstructUrl('/manageapikeys'), $spec->info->description);
|
||||
$spec->servers[0]->url = $this->AppContainer->get('UrlManager')->ConstructUrl('/api');
|
||||
|
||||
$spec->components->internalSchemas->ExposedEntity_NotIncludingNotEditable = clone $spec->components->internalSchemas->StringEnumTemplate;
|
||||
foreach ($spec->components->internalSchemas->ExposedEntity->enum as $value)
|
||||
$spec->components->schemas->ExposedEntity_IncludingUserEntities = clone $spec->components->schemas->ExposedEntity;
|
||||
foreach ($this->getUserfieldsService()->GetEntities() as $userEntity)
|
||||
{
|
||||
if (!in_array($value, $spec->components->internalSchemas->ExposedEntityNoEdit->enum))
|
||||
array_push($spec->components->schemas->ExposedEntity_IncludingUserEntities->enum, $userEntity);
|
||||
}
|
||||
|
||||
$spec->components->schemas->ExposedEntity_NotIncludingNotEditable = clone $spec->components->schemas->StringEnumTemplate;
|
||||
foreach ($spec->components->schemas->ExposedEntity->enum as $value)
|
||||
{
|
||||
if (!in_array($value, $spec->components->schemas->ExposedEntityNoEdit->enum))
|
||||
{
|
||||
array_push($spec->components->internalSchemas->ExposedEntity_NotIncludingNotEditable->enum, $value);
|
||||
array_push($spec->components->schemas->ExposedEntity_NotIncludingNotEditable->enum, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$spec->components->internalSchemas->ExposedEntity_NotIncludingNotDeletable = clone $spec->components->internalSchemas->StringEnumTemplate;
|
||||
foreach ($spec->components->internalSchemas->ExposedEntity->enum as $value)
|
||||
$spec->components->schemas->ExposedEntity_IncludingUserEntities_NotIncludingNotEditable = clone $spec->components->schemas->StringEnumTemplate;
|
||||
foreach ($spec->components->schemas->ExposedEntity_IncludingUserEntities->enum as $value)
|
||||
{
|
||||
if (!in_array($value, $spec->components->internalSchemas->ExposedEntityNoDelete->enum))
|
||||
if (!in_array($value, $spec->components->schemas->ExposedEntityNoEdit->enum))
|
||||
{
|
||||
array_push($spec->components->internalSchemas->ExposedEntity_NotIncludingNotDeletable->enum, $value);
|
||||
array_push($spec->components->schemas->ExposedEntity_IncludingUserEntities_NotIncludingNotEditable->enum, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$spec->components->internalSchemas->ExposedEntity_NotIncludingNotListable = clone $spec->components->internalSchemas->StringEnumTemplate;
|
||||
foreach ($spec->components->internalSchemas->ExposedEntity->enum as $value)
|
||||
$spec->components->schemas->ExposedEntity_NotIncludingNotDeletable = clone $spec->components->schemas->StringEnumTemplate;
|
||||
foreach ($spec->components->schemas->ExposedEntity->enum as $value)
|
||||
{
|
||||
if (!in_array($value, $spec->components->internalSchemas->ExposedEntityNoListing->enum))
|
||||
if (!in_array($value, $spec->components->schemas->ExposedEntityNoDelete->enum))
|
||||
{
|
||||
array_push($spec->components->internalSchemas->ExposedEntity_NotIncludingNotListable->enum, $value);
|
||||
array_push($spec->components->schemas->ExposedEntity_NotIncludingNotDeletable->enum, $value);
|
||||
}
|
||||
}
|
||||
|
||||
$spec->components->schemas->ExposedEntity_NotIncludingNotListable = clone $spec->components->schemas->StringEnumTemplate;
|
||||
foreach ($spec->components->schemas->ExposedEntity->enum as $value)
|
||||
{
|
||||
if (!in_array($value, $spec->components->schemas->ExposedEntityNoListing->enum))
|
||||
{
|
||||
array_push($spec->components->schemas->ExposedEntity_NotIncludingNotListable->enum, $value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,9 +85,4 @@ class OpenApiController extends BaseApiController
|
||||
{
|
||||
return $this->render($response, 'openapiui');
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
37
controllers/PrintApiController.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
use Grocy\Services\StockService;
|
||||
|
||||
class PrintApiController extends BaseApiController
|
||||
{
|
||||
public function PrintShoppingListThermal(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST);
|
||||
|
||||
$params = $request->getQueryParams();
|
||||
|
||||
$listId = 1;
|
||||
if (isset($params['list']))
|
||||
{
|
||||
$listId = $params['list'];
|
||||
}
|
||||
|
||||
$printHeader = true;
|
||||
if (isset($params['printHeader']))
|
||||
{
|
||||
$printHeader = ($params['printHeader'] === 'true');
|
||||
}
|
||||
$items = $this->getStockService()->GetShoppinglistInPrintableStrings($listId);
|
||||
return $this->ApiResponse($response, $this->getPrintService()->printShoppingList($printHeader, $items));
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,70 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class RecipesApiController extends BaseApiController
|
||||
{
|
||||
public function AddNotFulfilledProductsToShoppingList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST_ITEMS_ADD);
|
||||
|
||||
$requestBody = $this->GetParsedAndFilteredRequestBody($request);
|
||||
$excludedProductIds = null;
|
||||
|
||||
if ($requestBody !== null && array_key_exists('excludedProductIds', $requestBody))
|
||||
{
|
||||
$excludedProductIds = $requestBody['excludedProductIds'];
|
||||
}
|
||||
|
||||
$this->getRecipesService()->AddNotFulfilledProductsToShoppingList($args['recipeId'], $excludedProductIds);
|
||||
return $this->EmptyApiResponse($response);
|
||||
}
|
||||
|
||||
public function ConsumeRecipe(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_STOCK_CONSUME);
|
||||
|
||||
try
|
||||
{
|
||||
$this->getRecipesService()->ConsumeRecipe($args['recipeId']);
|
||||
return $this->EmptyApiResponse($response);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function GetRecipeFulfillment(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!isset($args['recipeId']))
|
||||
{
|
||||
return $this->FilteredApiResponse($response, $this->getRecipesService()->GetRecipesResolved(), $request->getQueryParams());
|
||||
}
|
||||
|
||||
$recipeResolved = FindObjectInArrayByPropertyValue($this->getRecipesService()->GetRecipesResolved(), 'recipe_id', $args['recipeId']);
|
||||
|
||||
if (!$recipeResolved)
|
||||
{
|
||||
throw new \Exception('Recipe does not exist');
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->ApiResponse($response, $recipeResolved);
|
||||
}
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
<?php
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
|
||||
class RecipesApiController extends BaseApiController
|
||||
{
|
||||
public function AddNotFulfilledProductsToShoppingList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST_ITEMS_ADD);
|
||||
|
||||
$requestBody = $this->GetParsedAndFilteredRequestBody($request);
|
||||
$excludedProductIds = null;
|
||||
|
||||
if ($requestBody !== null && array_key_exists('excludedProductIds', $requestBody))
|
||||
{
|
||||
$excludedProductIds = $requestBody['excludedProductIds'];
|
||||
}
|
||||
|
||||
$this->getRecipesService()->AddNotFulfilledProductsToShoppingList($args['recipeId'], $excludedProductIds);
|
||||
return $this->EmptyApiResponse($response);
|
||||
}
|
||||
|
||||
public function ConsumeRecipe(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_STOCK_CONSUME);
|
||||
|
||||
try
|
||||
{
|
||||
$this->getRecipesService()->ConsumeRecipe($args['recipeId']);
|
||||
return $this->EmptyApiResponse($response);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function GetRecipeFulfillment(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!isset($args['recipeId']))
|
||||
{
|
||||
return $this->FilteredApiResponse($response, $this->getRecipesService()->GetRecipesResolved(), $request->getQueryParams());
|
||||
}
|
||||
|
||||
$recipeResolved = FindObjectInArrayByPropertyValue($this->getRecipesService()->GetRecipesResolved(), 'recipe_id', $args['recipeId']);
|
||||
|
||||
if (!$recipeResolved)
|
||||
{
|
||||
throw new \Exception('Recipe does not exist');
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->ApiResponse($response, $recipeResolved);
|
||||
}
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function CopyRecipe(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
return $this->ApiResponse($response, [
|
||||
'created_object_id' => $this->getRecipesService()->CopyRecipe($args['recipeId'])
|
||||
]);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,11 +8,23 @@ class RecipesController extends BaseController
|
||||
{
|
||||
public function MealPlan(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$start = date('Y-m-d');
|
||||
if (isset($request->getQueryParams()['start']) && IsIsoDate($request->getQueryParams()['start']))
|
||||
{
|
||||
$start = $request->getQueryParams()['start'];
|
||||
}
|
||||
|
||||
$days = 6;
|
||||
if (isset($request->getQueryParams()['days']) && filter_var($request->getQueryParams()['days'], FILTER_VALIDATE_INT) !== false)
|
||||
{
|
||||
$days = $request->getQueryParams()['days'];
|
||||
}
|
||||
|
||||
$mealPlanWhereTimespan = "day BETWEEN DATE('$start') AND DATE('$start', '+$days days')";
|
||||
|
||||
$recipes = $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll();
|
||||
|
||||
$events = [];
|
||||
|
||||
foreach ($this->getDatabase()->meal_plan() as $mealPlanEntry)
|
||||
foreach ($this->getDatabase()->meal_plan()->where($mealPlanWhereTimespan) as $mealPlanEntry)
|
||||
{
|
||||
$recipe = FindObjectInArrayByPropertyValue($recipes, 'id', $mealPlanEntry['recipe_id']);
|
||||
$title = '';
|
||||
@@ -23,7 +35,6 @@ class RecipesController extends BaseController
|
||||
}
|
||||
|
||||
$productDetails = null;
|
||||
|
||||
if ($mealPlanEntry['product_id'] !== null)
|
||||
{
|
||||
$productDetails = $this->getStockService()->GetProductDetails($mealPlanEntry['product_id']);
|
||||
@@ -44,18 +55,20 @@ class RecipesController extends BaseController
|
||||
return $this->renderPage($response, 'mealplan', [
|
||||
'fullcalendarEventSources' => $events,
|
||||
'recipes' => $recipes,
|
||||
'internalRecipes' => $this->getDatabase()->recipes()->whereNot('type', RecipesService::RECIPE_TYPE_NORMAL)->fetchAll(),
|
||||
'recipesResolved' => $this->getRecipesService()->GetRecipesResolved(),
|
||||
'internalRecipes' => $this->getDatabase()->recipes()->where("id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan)")->fetchAll(),
|
||||
'recipesResolved' => $this->getRecipesService()->GetRecipesResolved2("recipe_id IN (SELECT recipe_id FROM meal_plan_internal_recipe_relation WHERE $mealPlanWhereTimespan)"),
|
||||
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved(),
|
||||
'mealplanSections' => $this->getDatabase()->meal_plan_sections()->orderBy('sort_number'),
|
||||
'usedMealplanSections' => $this->getDatabase()->meal_plan_sections()->where("id IN (SELECT section_id FROM meal_plan WHERE $mealPlanWhereTimespan)")->orderBy('sort_number')
|
||||
]);
|
||||
}
|
||||
|
||||
public function Overview(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$recipes = $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE');
|
||||
$recipesResolved = $this->getRecipesService()->GetRecipesResolved();
|
||||
$recipesResolved = $this->getRecipesService()->GetRecipesResolved('recipe_id > 0');
|
||||
|
||||
$selectedRecipe = null;
|
||||
|
||||
@@ -157,7 +170,7 @@ class RecipesController extends BaseController
|
||||
'mode' => 'create',
|
||||
'recipe' => $this->getDatabase()->recipes($args['recipeId']),
|
||||
'recipePos' => new \stdClass(),
|
||||
'products' => $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE'),
|
||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityUnitConversionsResolved' => $this->getDatabase()->quantity_unit_conversions_resolved()
|
||||
]);
|
||||
@@ -180,8 +193,27 @@ class RecipesController extends BaseController
|
||||
return $this->renderPage($response, 'recipessettings');
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
public function MealPlanSectionEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
parent::__construct($container);
|
||||
if ($args['sectionId'] == 'new')
|
||||
{
|
||||
return $this->renderPage($response, 'mealplansectionform', [
|
||||
'mode' => 'create'
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->renderPage($response, 'mealplansectionform', [
|
||||
'mealplanSection' => $this->getDatabase()->meal_plan_sections($args['sectionId']),
|
||||
'mode' => 'edit'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function MealPlanSectionsList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
return $this->renderPage($response, 'mealplansections', [
|
||||
'mealplanSections' => $this->getDatabase()->meal_plan_sections()->where('id > 0')->orderBy('sort_number')
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@@ -4,6 +4,8 @@ namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Controllers\Users\User;
|
||||
use Grocy\Services\StockService;
|
||||
use Grocy\Helpers\WebhookRunner;
|
||||
use Grocy\Helpers\Grocycode;
|
||||
|
||||
class StockApiController extends BaseApiController
|
||||
{
|
||||
@@ -138,8 +140,14 @@ class StockApiController extends BaseApiController
|
||||
{
|
||||
$transactionType = $requestBody['transactiontype'];
|
||||
}
|
||||
$runPrinterWebhook = false;
|
||||
if (array_key_exists('print_stock_label', $requestBody) && intval($requestBody['print_stock_label']))
|
||||
{
|
||||
$runPrinterWebhook = intval($requestBody['print_stock_label']);
|
||||
}
|
||||
|
||||
$transactionId = $this->getStockService()->AddProduct($args['productId'], $requestBody['amount'], $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId, $shoppingLocationId, $unusedTransactionId, $runPrinterWebhook);
|
||||
|
||||
$transactionId = $this->getStockService()->AddProduct($args['productId'], $requestBody['amount'], $bestBeforeDate, $transactionType, $purchasedDate, $price, $locationId, $shoppingLocationId);
|
||||
$args['transactionId'] = $transactionId;
|
||||
return $this->StockTransactions($request, $response, $args);
|
||||
}
|
||||
@@ -172,6 +180,7 @@ class StockApiController extends BaseApiController
|
||||
|
||||
$listId = 1;
|
||||
$amount = 1;
|
||||
$quId = -1;
|
||||
$productId = null;
|
||||
$note = null;
|
||||
|
||||
@@ -195,12 +204,17 @@ class StockApiController extends BaseApiController
|
||||
$note = $requestBody['note'];
|
||||
}
|
||||
|
||||
if (array_key_exists('qu_id', $requestBody) && !empty($requestBody['qu_id']))
|
||||
{
|
||||
$quId = $requestBody['qu_id'];
|
||||
}
|
||||
|
||||
if ($productId == null)
|
||||
{
|
||||
throw new \Exception('No product id was supplied');
|
||||
}
|
||||
|
||||
$this->getStockService()->AddProductToShoppingList($productId, $amount, $note, $listId);
|
||||
$this->getStockService()->AddProductToShoppingList($productId, $amount, $quId, $note, $listId);
|
||||
return $this->EmptyApiResponse($response);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
@@ -604,6 +618,60 @@ class StockApiController extends BaseApiController
|
||||
return $this->FilteredApiResponse($response, $this->getStockService()->GetProductStockLocations($args['productId'], $allowSubproductSubstitution), $request->getQueryParams());
|
||||
}
|
||||
|
||||
public function ProductPrintLabel(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$product = $this->getDatabase()->products()->where('id', $args['productId'])->fetch();
|
||||
|
||||
$webhookData = array_merge([
|
||||
'product' => $product->name,
|
||||
'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $product->id)),
|
||||
], GROCY_LABEL_PRINTER_PARAMS);
|
||||
|
||||
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
||||
{
|
||||
(new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON);
|
||||
}
|
||||
|
||||
return $this->ApiResponse($response, $webhookData);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function StockEntryPrintLabel(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
try
|
||||
{
|
||||
$stockEntry = $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch();
|
||||
$product = $this->getDatabase()->products()->where('id', $stockEntry->product_id)->fetch();
|
||||
|
||||
$webhookData = array_merge([
|
||||
'product' => $product->name,
|
||||
'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id])),
|
||||
], GROCY_LABEL_PRINTER_PARAMS);
|
||||
|
||||
if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
|
||||
{
|
||||
$webhookData['due_date'] = $this->getLocalizationService()->__t('DD') . ': ' . $stockEntry->best_before_date;
|
||||
}
|
||||
|
||||
if (GROCY_LABEL_PRINTER_RUN_SERVER)
|
||||
{
|
||||
(new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON);
|
||||
}
|
||||
|
||||
return $this->ApiResponse($response, $webhookData);
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function RemoveProductFromShoppingList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
User::checkPermission($request, User::PERMISSION_SHOPPINGLIST_ITEMS_DELETE);
|
||||
@@ -794,9 +862,4 @@ class StockApiController extends BaseApiController
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
@@ -2,14 +2,17 @@
|
||||
|
||||
namespace Grocy\Controllers;
|
||||
|
||||
use Grocy\Helpers\Grocycode;
|
||||
use Grocy\Services\RecipesService;
|
||||
|
||||
class StockController extends BaseController
|
||||
{
|
||||
use GrocycodeTrait;
|
||||
|
||||
public function Consume(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
return $this->renderPage($response, 'consume', [
|
||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'),
|
||||
'products' => $this->getDatabase()->products()->where('active = 1')->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)')->orderBy('name'),
|
||||
'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(),
|
||||
'recipes' => $this->getDatabase()->recipes()->where('type', RecipesService::RECIPE_TYPE_NORMAL)->orderBy('name', 'COLLATE NOCASE'),
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||
@@ -32,14 +35,31 @@ class StockController extends BaseController
|
||||
|
||||
public function Journal(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if (isset($request->getQueryParams()['months']) && filter_var($request->getQueryParams()['months'], FILTER_VALIDATE_INT) !== false)
|
||||
{
|
||||
$months = $request->getQueryParams()['months'];
|
||||
$where = "row_created_timestamp > DATE(DATE('now', 'localtime'), '-$months months')";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default 6 months
|
||||
$where = "row_created_timestamp > DATE(DATE('now', 'localtime'), '-6 months')";
|
||||
}
|
||||
|
||||
if (isset($request->getQueryParams()['product']) && filter_var($request->getQueryParams()['product'], FILTER_VALIDATE_INT) !== false)
|
||||
{
|
||||
$productId = $request->getQueryParams()['product'];
|
||||
$where .= " AND product_id = $productId";
|
||||
}
|
||||
|
||||
$usersService = $this->getUsersService();
|
||||
|
||||
return $this->renderPage($response, 'stockjournal', [
|
||||
'stockLog' => $this->getDatabase()->uihelper_stock_journal()->orderBy('row_created_timestamp', 'DESC'),
|
||||
'stockLog' => $this->getDatabase()->uihelper_stock_journal()->where($where)->orderBy('row_created_timestamp', 'DESC'),
|
||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||
'users' => $usersService->GetUsersAsDto(),
|
||||
'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_'),
|
||||
'transactionTypes' => GetClassConstants('\Grocy\Services\StockService', 'TRANSACTION_TYPE_')
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -170,6 +190,12 @@ class StockController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
public function ProductGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$gc = new Grocycode(Grocycode::PRODUCT, $args['productId']);
|
||||
return $this->ServeGrocycodeImage($request, $response, $gc);
|
||||
}
|
||||
|
||||
public function ProductGroupEditForm(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if ($args['productGroupId'] == 'new')
|
||||
@@ -201,15 +227,19 @@ class StockController extends BaseController
|
||||
|
||||
public function ProductsList(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
if (isset($request->getQueryParams()['include_disabled']))
|
||||
$products = $this->getDatabase()->products();
|
||||
if (!isset($request->getQueryParams()['include_disabled']))
|
||||
{
|
||||
$products = $this->getDatabase()->products()->orderBy('name', 'COLLATE NOCASE');
|
||||
$products = $products->where('active = 1');
|
||||
}
|
||||
else
|
||||
|
||||
if (isset($request->getQueryParams()['only_in_stock']))
|
||||
{
|
||||
$products = $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE');
|
||||
$products = $products->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)');
|
||||
}
|
||||
|
||||
$products = $products->orderBy('name', 'COLLATE NOCASE');
|
||||
|
||||
return $this->renderPage($response, 'products', [
|
||||
'products' => $products,
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||
@@ -428,6 +458,22 @@ class StockController extends BaseController
|
||||
]);
|
||||
}
|
||||
|
||||
public function StockEntryGrocycodeImage(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$stockEntry = $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch();
|
||||
$gc = new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id]);
|
||||
return $this->ServeGrocycodeImage($request, $response, $gc);
|
||||
}
|
||||
|
||||
public function StockEntryGrocycodeLabel(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$stockEntry = $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch();
|
||||
return $this->renderPage($response, 'stockentrylabel', [
|
||||
'stockEntry' => $stockEntry,
|
||||
'product' => $this->getDatabase()->products($stockEntry->product_id),
|
||||
]);
|
||||
}
|
||||
|
||||
public function StockSettings(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
return $this->renderPage($response, 'stocksettings', [
|
||||
@@ -458,7 +504,7 @@ class StockController extends BaseController
|
||||
public function Transfer(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
return $this->renderPage($response, 'transfer', [
|
||||
'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'products' => $this->getDatabase()->products()->where('active = 1')->where('id IN (SELECT product_id from stock_current WHERE amount_aggregated > 0)')->orderBy('name', 'COLLATE NOCASE'),
|
||||
'barcodes' => $this->getDatabase()->product_barcodes_comma_separated(),
|
||||
'locations' => $this->getDatabase()->locations()->orderBy('name', 'COLLATE NOCASE'),
|
||||
'quantityUnits' => $this->getDatabase()->quantity_units()->orderBy('name', 'COLLATE NOCASE'),
|
||||
@@ -466,11 +512,6 @@ class StockController extends BaseController
|
||||
]);
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
public function JournalSummary(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
$entries = $this->getDatabase()->uihelper_stock_journal_summary();
|
||||
|
@@ -85,8 +85,8 @@ class SystemApiController extends BaseApiController
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
public function GetLocalizationStrings(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
|
||||
{
|
||||
parent::__construct($container);
|
||||
return $this->ApiResponse($response, json_decode($this->getLocalizationService()->GetPoAsJsonString()), true);
|
||||
}
|
||||
}
|
||||
|
@@ -35,11 +35,6 @@ class SystemController extends BaseController
|
||||
return $response->withRedirect($this->AppContainer->get('UrlManager')->ConstructUrl($this->GetEntryPageRelative()));
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the entry page of the application based on the value of the entry page setting.
|
||||
*
|
||||
|
@@ -49,9 +49,4 @@ class TasksApiController extends BaseApiController
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
@@ -83,9 +83,4 @@ class TasksController extends BaseController
|
||||
{
|
||||
return $this->renderPage($response, 'taskssettings');
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
@@ -10,13 +10,17 @@ class User
|
||||
const PERMISSION_ADMIN = 'ADMIN';
|
||||
|
||||
const PERMISSION_BATTERIES = 'BATTERIES';
|
||||
|
||||
const PERMISSION_BATTERIES_TRACK_CHARGE_CYCLE = 'BATTERIES_TRACK_CHARGE_CYCLE';
|
||||
|
||||
const PERMISSION_BATTERIES_UNDO_CHARGE_CYCLE = 'BATTERIES_UNDO_CHARGE_CYCLE';
|
||||
|
||||
const PERMISSION_CALENDAR = 'CALENDAR';
|
||||
|
||||
const PERMISSION_CHORES = 'CHORES';
|
||||
|
||||
const PERMISSION_CHORE_TRACK_EXECUTION = 'CHORE_TRACK_EXECUTION';
|
||||
|
||||
const PERMISSION_CHORE_UNDO_EXECUTION = 'CHORE_UNDO_EXECUTION';
|
||||
|
||||
const PERMISSION_EQUIPMENT = 'EQUIPMENT';
|
||||
@@ -24,30 +28,50 @@ class User
|
||||
const PERMISSION_MASTER_DATA_EDIT = 'MASTER_DATA_EDIT';
|
||||
|
||||
const PERMISSION_RECIPES = 'RECIPES';
|
||||
|
||||
const PERMISSION_RECIPES_MEALPLAN = 'RECIPES_MEALPLAN';
|
||||
|
||||
const PERMISSION_SHOPPINGLIST = 'SHOPPINGLIST';
|
||||
|
||||
const PERMISSION_SHOPPINGLIST_ITEMS_ADD = 'SHOPPINGLIST_ITEMS_ADD';
|
||||
|
||||
const PERMISSION_SHOPPINGLIST_ITEMS_DELETE = 'SHOPPINGLIST_ITEMS_DELETE';
|
||||
|
||||
const PERMISSION_STOCK = 'STOCK';
|
||||
|
||||
const PERMISSION_STOCK_CONSUME = 'STOCK_CONSUME';
|
||||
|
||||
const PERMISSION_STOCK_EDIT = 'STOCK_EDIT';
|
||||
|
||||
const PERMISSION_STOCK_INVENTORY = 'STOCK_INVENTORY';
|
||||
|
||||
const PERMISSION_STOCK_OPEN = 'STOCK_OPEN';
|
||||
|
||||
const PERMISSION_STOCK_PURCHASE = 'STOCK_PURCHASE';
|
||||
|
||||
const PERMISSION_STOCK_TRANSFER = 'STOCK_TRANSFER';
|
||||
|
||||
const PERMISSION_TASKS = 'TASKS';
|
||||
|
||||
const PERMISSION_TASKS_MARK_COMPLETED = 'TASKS_MARK_COMPLETED';
|
||||
|
||||
const PERMISSION_TASKS_UNDO_EXECUTION = 'TASKS_UNDO_EXECUTION';
|
||||
|
||||
const PERMISSION_USERS = 'USERS';
|
||||
|
||||
const PERMISSION_USERS_CREATE = 'USERS_CREATE';
|
||||
|
||||
const PERMISSION_USERS_EDIT = 'USERS_EDIT';
|
||||
|
||||
const PERMISSION_USERS_EDIT_SELF = 'USERS_EDIT_SELF';
|
||||
|
||||
const PERMISSION_USERS_READ = 'USERS_READ';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = DatabaseService::getInstance()->GetDbConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \LessQL\Database|null
|
||||
*/
|
||||
@@ -59,11 +83,6 @@ class User
|
||||
return $user->getPermissionList();
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = DatabaseService::getInstance()->GetDbConnection();
|
||||
}
|
||||
|
||||
public static function checkPermission($request, string ...$permissions): void
|
||||
{
|
||||
$user = new self();
|
||||
|
@@ -231,9 +231,4 @@ class UsersApiController extends BaseApiController
|
||||
return $this->GenericErrorResponse($response, $ex->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(\DI\Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
}
|
||||
}
|
||||
|
66
docs/grocycode.md
Normal file
@@ -0,0 +1,66 @@
|
||||
grocycode
|
||||
==========
|
||||
|
||||
grocycode is, in essence, a simple way to reference to arbitrary grocy entities.
|
||||
Each grocycode includes a magic, an entitiy identifier, an id and an ordered set of extra data.
|
||||
It is supported to be entered anywhere grocy expects one to read a barcode, but can also reference
|
||||
grocy-internal properties like specific stock entries, or specific batteries.
|
||||
|
||||
Serialization
|
||||
----
|
||||
|
||||
There are three mandatory parts in a grocycode:
|
||||
|
||||
1. The magic `grcy`
|
||||
2. An entity identifer matching the regular expression `[a-z]+` (that is, lowercase english alphabet without any fancy accents, minimum length 1 character).
|
||||
3. An object identifer matching the regular expression `[0-9]+`
|
||||
|
||||
Optionally, any number of further data without format restrictions besides not containing any double colons [0] may be appended.
|
||||
|
||||
These parts are then linearly appended, seperated by a double colon `:`.
|
||||
|
||||
Entity Identifers
|
||||
----
|
||||
|
||||
Currently, there are three different entity types defined:
|
||||
|
||||
- `p` for Products
|
||||
- `b` for Batteries
|
||||
- `c` for Chores
|
||||
|
||||
Example
|
||||
----
|
||||
|
||||
In this example, we encode a *Product* with ID *13*, which results in `grcy:p:13` when serialized.
|
||||
|
||||
Product grocycodes
|
||||
----
|
||||
|
||||
Product grocycodes extend the data format to include an optional stock id, thus may reference a specific stock entry directly.
|
||||
|
||||
Example: `grcy:p:13:60bf8b5244b04`
|
||||
|
||||
Battery grocycodes
|
||||
----
|
||||
|
||||
Currently, Battery grocycodes do not define any extra fields.
|
||||
|
||||
Chore grocycodes
|
||||
----
|
||||
|
||||
Currently, Chore grocycodes do not define any extra fields.
|
||||
|
||||
Visual Encoding
|
||||
----
|
||||
|
||||
Grocy uses DataMatrix 2D (or alternatively Code128 1D) Barcodes to encode grocycodes into a visual representation. In principle, there is no problem with using
|
||||
other encoding formats like QR codes; however DataMatrix uses less space for the same information and redundancy and is a bit
|
||||
easier read by 2D barcode scanners, especially on non-flat surfaces.
|
||||
|
||||
You can pick up cheap-ish used scanners from ebay (about 45€ in germany). Make sure to set them to the correct keyboard emulation,
|
||||
so that the double colons get entered correctly.
|
||||
|
||||
|
||||
Notes
|
||||
---
|
||||
[0]: Obviously, it needs to be encoded into some usable visual representation and then read. So probably you only want to encode stuff that can be typed on a keyboard.
|
40
docs/label-printing.md
Normal file
@@ -0,0 +1,40 @@
|
||||
Label printing
|
||||
====
|
||||
|
||||
To enable label printing, set `FEATURE_FLAG_LABEL_PRINTER` to `true`in your `config.php`. You also need to provide a webhook target that is responsible for printing.
|
||||
|
||||
Why webhook?
|
||||
---
|
||||
|
||||
Label printers come in all shapes and forms, and your particular one is probably not the one used by the author of this feature. Also, grocy may does not have a
|
||||
direct connection to a local label printer (e.g. grocy is hosted in a cloud vps). Thus, a lightweight implementation is provided by grocy: whenever something
|
||||
should print, a POST request to a configured URL is made. The target then is responsible for label printing.
|
||||
|
||||
Reference implementation
|
||||
---
|
||||
|
||||
The webhook was developed and tested against a Brother QL-600 label printer, using endless 62mm label paper. The webhook provider implementation was
|
||||
implemented into [a fork of brother_ql_web](https://github.com/mistressofjellyfish/brother_ql_web).
|
||||
|
||||
Webhook request
|
||||
---
|
||||
|
||||
Requests can be configured to be sent server-side (that is, from the machine hosting grocy through GuzzleHttp) or by an AJAX request directly from the browser.
|
||||
The latter is neccesary for situations where the grocy hosting machine cannot reach your label printer, however server-side requests are a bit faster and
|
||||
tend to be more stable.
|
||||
|
||||
Both methods fire this request upon printing:
|
||||
|
||||
```
|
||||
POST /your/printing/api/endpoint HTTP/1.1
|
||||
|
||||
product=<productname>&grocycode=grocy:x:xxx&due_date=DD:%2021-06-09&...
|
||||
|
||||
```
|
||||
|
||||
If specified, the request body may also be JSON encoded, however the fields stay the same.
|
||||
|
||||
Additional POST parameters (like the font to use) may be supplied in `config.php`. Keep in mind that these config values will be distributed to all clients on all requests
|
||||
if the webhook is configured to run client-side.
|
||||
|
||||
The webhook receiver is required to layout and print the resulting label.
|
@@ -52,6 +52,9 @@
|
||||
},
|
||||
{
|
||||
"name": "Files"
|
||||
},
|
||||
{
|
||||
"name": "Print"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
@@ -181,6 +184,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/system/localization-strings": {
|
||||
"get": {
|
||||
"summary": "Returns all localization strings (in the by the user desired language)",
|
||||
"tags": [
|
||||
"System"
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The operation was successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"description": "A gettext JSON representation"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/system/log-missing-localization": {
|
||||
"post": {
|
||||
"summary": "Logs a missing localization string",
|
||||
@@ -229,7 +253,7 @@
|
||||
"required": true,
|
||||
"description": "A valid entity name",
|
||||
"schema": {
|
||||
"$ref": "#/components/internalSchemas/ExposedEntity_NotIncludingNotListable"
|
||||
"$ref": "#/components/schemas/ExposedEntity_NotIncludingNotListable"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -318,7 +342,7 @@
|
||||
"required": true,
|
||||
"description": "A valid entity name",
|
||||
"schema": {
|
||||
"$ref": "#/components/internalSchemas/ExposedEntity_NotIncludingNotEditable"
|
||||
"$ref": "#/components/schemas/ExposedEntity_NotIncludingNotEditable"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -402,7 +426,7 @@
|
||||
"required": true,
|
||||
"description": "A valid entity name",
|
||||
"schema": {
|
||||
"$ref": "#/components/internalSchemas/ExposedEntity_NotIncludingNotListable"
|
||||
"$ref": "#/components/schemas/ExposedEntity_NotIncludingNotListable"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -486,7 +510,7 @@
|
||||
"required": true,
|
||||
"description": "A valid entity name",
|
||||
"schema": {
|
||||
"$ref": "#/components/internalSchemas/ExposedEntity_NotIncludingNotEditable"
|
||||
"$ref": "#/components/schemas/ExposedEntity_NotIncludingNotEditable"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -563,7 +587,7 @@
|
||||
"required": true,
|
||||
"description": "A valid entity name",
|
||||
"schema": {
|
||||
"$ref": "#/components/internalSchemas/ExposedEntity_NotIncludingNotDeletable"
|
||||
"$ref": "#/components/schemas/ExposedEntity_NotIncludingNotDeletable"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -606,7 +630,7 @@
|
||||
"required": true,
|
||||
"description": "A valid entity name",
|
||||
"schema": {
|
||||
"$ref": "#/components/internalSchemas/ExposedEntity"
|
||||
"$ref": "#/components/schemas/ExposedEntity_IncludingUserEntities"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -655,7 +679,7 @@
|
||||
"required": true,
|
||||
"description": "A valid entity name",
|
||||
"schema": {
|
||||
"$ref": "#/components/internalSchemas/ExposedEntity_NotIncludingNotEditable"
|
||||
"$ref": "#/components/schemas/ExposedEntity_IncludingUserEntities_NotIncludingNotEditable"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -710,7 +734,7 @@
|
||||
"required": true,
|
||||
"description": "The file group",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
"$ref": "#/components/schemas/FileGroups"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -790,7 +814,7 @@
|
||||
"required": true,
|
||||
"description": "The file group",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
"$ref": "#/components/schemas/FileGroups"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -841,7 +865,7 @@
|
||||
"required": true,
|
||||
"description": "The file group",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
"$ref": "#/components/schemas/FileGroups"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -1402,7 +1426,7 @@
|
||||
"in": "path",
|
||||
"name": "entryId",
|
||||
"required": true,
|
||||
"description": "A valid stock row id",
|
||||
"description": "A valid stock entry id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
@@ -1441,7 +1465,7 @@
|
||||
"in": "path",
|
||||
"name": "entryId",
|
||||
"required": true,
|
||||
"description": "A valid stock row id",
|
||||
"description": "A valid stock entry id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
@@ -1529,6 +1553,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/stock/entry/{entryId}/printlabel": {
|
||||
"get": {
|
||||
"summary": "Prints the grocycode / stock entry label of the given entry on the configured label printer",
|
||||
"tags": [
|
||||
"Stock"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "entryId",
|
||||
"required": true,
|
||||
"description": "A valid stock entry id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The operation was successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"description": "WebHook data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The operation was not successful (possible errors are: Not existing stock entry, error on WebHook execution)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error400"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/stock/volatile": {
|
||||
"get": {
|
||||
"summary": "Returns all products which are due soon, overdue, expired or currently missing",
|
||||
@@ -1834,7 +1900,7 @@
|
||||
"description": "The due date of the product to add, when omitted, the current date is used"
|
||||
},
|
||||
"transaction_type": {
|
||||
"$ref": "#/components/internalSchemas/StockTransactionType"
|
||||
"$ref": "#/components/schemas/StockTransactionType"
|
||||
},
|
||||
"price": {
|
||||
"type": "number",
|
||||
@@ -1850,6 +1916,10 @@
|
||||
"type": "number",
|
||||
"format": "integer",
|
||||
"description": "If omitted, no store will be affected"
|
||||
},
|
||||
"print_stock_label": {
|
||||
"type": "boolean",
|
||||
"description": "True when the stock entry label should be printed"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
@@ -1918,7 +1988,7 @@
|
||||
"description": "The amount to remove - please note that when tare weight handling for the product is enabled, this needs to be the amount including the container weight (gross), the amount to be posted will be automatically calculated based on what is in stock and the defined tare weight"
|
||||
},
|
||||
"transaction_type": {
|
||||
"$ref": "#/components/internalSchemas/StockTransactionType"
|
||||
"$ref": "#/components/schemas/StockTransactionType"
|
||||
},
|
||||
"spoiled": {
|
||||
"type": "boolean",
|
||||
@@ -2213,6 +2283,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/stock/products/{productId}/printlabel": {
|
||||
"get": {
|
||||
"summary": "Prints the grocycode label of the given product on the configured label printer",
|
||||
"tags": [
|
||||
"Stock"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "productId",
|
||||
"required": true,
|
||||
"description": "A valid product id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The operation was successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"description": "WebHook data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The operation was not successful (possible errors are: Not existing product, error on WebHook execution)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error400"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/stock/products/{productIdToKeep}/merge/{productIdToRemove}": {
|
||||
"post": {
|
||||
"summary": "Merges two products into one",
|
||||
@@ -2332,7 +2444,7 @@
|
||||
"description": "The due date of the product to add, when omitted, the current date is used"
|
||||
},
|
||||
"transaction_type": {
|
||||
"$ref": "#/components/internalSchemas/StockTransactionType"
|
||||
"$ref": "#/components/schemas/StockTransactionType"
|
||||
},
|
||||
"price": {
|
||||
"type": "number",
|
||||
@@ -2411,7 +2523,7 @@
|
||||
"description": "The amount to remove - please note that when tare weight handling for the product is enabled, this needs to be the amount including the container weight (gross), the amount to be posted will be automatically calculated based on what is in stock and the defined tare weight"
|
||||
},
|
||||
"transaction_type": {
|
||||
"$ref": "#/components/internalSchemas/StockTransactionType"
|
||||
"$ref": "#/components/schemas/StockTransactionType"
|
||||
},
|
||||
"spoiled": {
|
||||
"type": "boolean",
|
||||
@@ -3350,6 +3462,54 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/recipes/{recipeId}/copy": {
|
||||
"post": {
|
||||
"summary": "Copies a recipe",
|
||||
"tags": [
|
||||
"Recipes"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "recipeId",
|
||||
"required": true,
|
||||
"description": "A valid recipe id of the recipe to copy",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The operation was successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_object_id": {
|
||||
"type": "number",
|
||||
"format": "integer",
|
||||
"description": "The id of the created recipe"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The operation was not successful (possible errors are: Invalid recipe id)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error400"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chores": {
|
||||
"get": {
|
||||
"summary": "Returns all chores incl. the next estimated execution time per chore",
|
||||
@@ -3576,6 +3736,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chores/{choreId}/printlabel": {
|
||||
"get": {
|
||||
"summary": "Prints the grocycode label of the given chore on the configured label printer",
|
||||
"tags": [
|
||||
"Chores"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "choreId",
|
||||
"required": true,
|
||||
"description": "A valid chore id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The operation was successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"description": "WebHook data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The operation was not successful (possible errors are: Not existing chore, error on WebHook execution)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error400"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/batteries": {
|
||||
"get": {
|
||||
"summary": "Returns all batteries incl. the next estimated charge time per battery",
|
||||
@@ -3756,6 +3958,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/batteries/{batteryId}/printlabel": {
|
||||
"get": {
|
||||
"summary": "Prints the grocycode label of the given battery on the configured label printer",
|
||||
"tags": [
|
||||
"Batteries"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "batteryId",
|
||||
"required": true,
|
||||
"description": "A valid battery id",
|
||||
"schema": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The operation was successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"description": "WebHook data"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The operation was not successful (possible errors are: Not existing battery, error on WebHook execution)",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error400"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/tasks": {
|
||||
"get": {
|
||||
"summary": "Returns all tasks which are not done yet",
|
||||
@@ -3778,13 +4022,13 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "An array of Task objects",
|
||||
"description": "An array of CurrentTaskResponse objects",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Task"
|
||||
"$ref": "#/components/schemas/CurrentTaskResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3942,84 +4186,66 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/print/shoppinglist/thermal": {
|
||||
"get": {
|
||||
"summary": "Prints the shoppinglist with a thermal printer",
|
||||
"tags": [
|
||||
"Print"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "list",
|
||||
"required": false,
|
||||
"description": "Shopping list id",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"default": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "printHeader",
|
||||
"required": false,
|
||||
"description": "Prints grocy logo if true",
|
||||
"schema": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Returns OK if the printing was successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"result": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "The operation was not successful",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/Error400"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"internalSchemas": {
|
||||
"ExposedEntity": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"products",
|
||||
"chores",
|
||||
"product_barcodes",
|
||||
"batteries",
|
||||
"locations",
|
||||
"quantity_units",
|
||||
"quantity_unit_conversions",
|
||||
"shopping_list",
|
||||
"shopping_lists",
|
||||
"shopping_locations",
|
||||
"recipes",
|
||||
"recipes_pos",
|
||||
"recipes_nestings",
|
||||
"tasks",
|
||||
"task_categories",
|
||||
"product_groups",
|
||||
"equipment",
|
||||
"api_keys",
|
||||
"userfields",
|
||||
"userentities",
|
||||
"userobjects",
|
||||
"meal_plan",
|
||||
"stock_log",
|
||||
"stock",
|
||||
"stock_current_locations",
|
||||
"api_keys"
|
||||
]
|
||||
},
|
||||
"ExposedEntityNoListing": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"api_keys"
|
||||
]
|
||||
},
|
||||
"ExposedEntityNoEdit": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stock_log",
|
||||
"api_keys",
|
||||
"stock",
|
||||
"stock_current_locations"
|
||||
]
|
||||
},
|
||||
"ExposedEntityNoDelete": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stock_log",
|
||||
"stock",
|
||||
"stock_current_locations"
|
||||
]
|
||||
},
|
||||
"ExposedEntityEditRequiresAdmin": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"api_keys"
|
||||
]
|
||||
},
|
||||
"StockTransactionType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"purchase",
|
||||
"consume",
|
||||
"inventory-correction",
|
||||
"product-opened"
|
||||
]
|
||||
},
|
||||
"StringEnumTemplate": {
|
||||
"type": "string",
|
||||
"enum": []
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"Product": {
|
||||
"type": "object",
|
||||
@@ -4386,6 +4612,10 @@
|
||||
"spoil_rate_percent": {
|
||||
"type": "number",
|
||||
"format": "number"
|
||||
},
|
||||
"has_childs": {
|
||||
"type": "boolean",
|
||||
"description": "True when the product is a parent products of others"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
@@ -4716,6 +4946,9 @@
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"shopping_list_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"product_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
@@ -4900,7 +5133,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"transaction_type": {
|
||||
"$ref": "#/components/internalSchemas/StockTransactionType"
|
||||
"$ref": "#/components/schemas/StockTransactionType"
|
||||
},
|
||||
"row_created_timestamp": {
|
||||
"type": "string",
|
||||
@@ -4948,7 +5181,7 @@
|
||||
"default": false
|
||||
},
|
||||
"transaction_type": {
|
||||
"$ref": "#/components/internalSchemas/StockTransactionType"
|
||||
"$ref": "#/components/schemas/StockTransactionType"
|
||||
},
|
||||
"row_created_timestamp": {
|
||||
"type": "string",
|
||||
@@ -4998,7 +5231,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"transaction_type": {
|
||||
"$ref": "#/components/internalSchemas/StockTransactionType"
|
||||
"$ref": "#/components/schemas/StockTransactionType"
|
||||
}
|
||||
},
|
||||
"example": {
|
||||
@@ -5087,14 +5320,26 @@
|
||||
"chore_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"chore_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"last_tracked_time": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"track_date_only": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"next_estimated_execution_time": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "The next estimated execution time of this chore, 2999-12-31 23:59:59 when the given chore has a period_type of manually"
|
||||
},
|
||||
"next_execution_assigned_to_user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"next_execution_assigned_user": {
|
||||
"$ref": "#/components/schemas/UserDto"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5196,6 +5441,65 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"TaskCategory": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"row_created_timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
}
|
||||
}
|
||||
},
|
||||
"CurrentTaskResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"due_date": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"done": {
|
||||
"type": "integer"
|
||||
},
|
||||
"done_timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"category_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"assigned_to_user_id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"row_created_timestamp": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"assigned_to_user": {
|
||||
"$ref": "#/components/schemas/UserDto"
|
||||
},
|
||||
"category": {
|
||||
"$ref": "#/components/schemas/TaskCategory"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DbChangedTimeResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -5246,6 +5550,94 @@
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ExposedEntity": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"products",
|
||||
"chores",
|
||||
"product_barcodes",
|
||||
"batteries",
|
||||
"locations",
|
||||
"quantity_units",
|
||||
"quantity_unit_conversions",
|
||||
"shopping_list",
|
||||
"shopping_lists",
|
||||
"shopping_locations",
|
||||
"recipes",
|
||||
"recipes_pos",
|
||||
"recipes_nestings",
|
||||
"tasks",
|
||||
"task_categories",
|
||||
"product_groups",
|
||||
"equipment",
|
||||
"api_keys",
|
||||
"userfields",
|
||||
"userentities",
|
||||
"userobjects",
|
||||
"meal_plan",
|
||||
"stock_log",
|
||||
"stock",
|
||||
"stock_current_locations",
|
||||
"chores_log",
|
||||
"meal_plan_sections"
|
||||
]
|
||||
},
|
||||
"ExposedEntityNoListing": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"api_keys"
|
||||
]
|
||||
},
|
||||
"ExposedEntityNoEdit": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stock_log",
|
||||
"api_keys",
|
||||
"stock",
|
||||
"stock_current_locations",
|
||||
"chores_log"
|
||||
]
|
||||
},
|
||||
"ExposedEntityNoDelete": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"stock_log",
|
||||
"stock",
|
||||
"stock_current_locations",
|
||||
"chores_log"
|
||||
]
|
||||
},
|
||||
"ExposedEntityEditRequiresAdmin": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"api_keys"
|
||||
]
|
||||
},
|
||||
"StockTransactionType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"purchase",
|
||||
"consume",
|
||||
"inventory-correction",
|
||||
"product-opened"
|
||||
]
|
||||
},
|
||||
"FileGroups": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"equipmentmanuals",
|
||||
"recipepictures",
|
||||
"productpictures",
|
||||
"userfiles",
|
||||
"userpictures"
|
||||
]
|
||||
},
|
||||
"StringEnumTemplate": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
""
|
||||
]
|
||||
}
|
||||
},
|
||||
"securitySchemes": {
|
||||
|
@@ -4,6 +4,12 @@ namespace Grocy\Helpers;
|
||||
|
||||
abstract class BaseBarcodeLookupPlugin
|
||||
{
|
||||
final public function __construct($locations, $quantityUnits)
|
||||
{
|
||||
$this->Locations = $locations;
|
||||
$this->QuantityUnits = $quantityUnits;
|
||||
}
|
||||
|
||||
protected $Locations;
|
||||
|
||||
protected $QuantityUnits;
|
||||
@@ -50,28 +56,24 @@ abstract class BaseBarcodeLookupPlugin
|
||||
|
||||
// Check referenced entity ids are valid
|
||||
$locationId = $pluginOutput['location_id'];
|
||||
|
||||
if (FindObjectInArrayByPropertyValue($this->Locations, 'id', $locationId) === null)
|
||||
{
|
||||
throw new \Exception("Location $locationId is not a valid location id");
|
||||
}
|
||||
|
||||
$quIdPurchase = $pluginOutput['qu_id_purchase'];
|
||||
|
||||
if (FindObjectInArrayByPropertyValue($this->QuantityUnits, 'id', $quIdPurchase) === null)
|
||||
{
|
||||
throw new \Exception("Location $quIdPurchase is not a valid quantity unit id");
|
||||
}
|
||||
|
||||
$quIdStock = $pluginOutput['qu_id_stock'];
|
||||
|
||||
if (FindObjectInArrayByPropertyValue($this->QuantityUnits, 'id', $quIdStock) === null)
|
||||
{
|
||||
throw new \Exception("Location $quIdStock is not a valid quantity unit id");
|
||||
}
|
||||
|
||||
$quFactor = $pluginOutput['qu_factor_purchase_to_stock'];
|
||||
|
||||
if (empty($quFactor) || !is_numeric($quFactor))
|
||||
{
|
||||
throw new \Exception('Quantity unit factor is empty or not a number');
|
||||
@@ -80,11 +82,5 @@ abstract class BaseBarcodeLookupPlugin
|
||||
return $pluginOutput;
|
||||
}
|
||||
|
||||
final public function __construct($locations, $quantityUnits)
|
||||
{
|
||||
$this->Locations = $locations;
|
||||
$this->QuantityUnits = $quantityUnits;
|
||||
}
|
||||
|
||||
abstract protected function ExecuteLookup($barcode);
|
||||
}
|
||||
|
146
helpers/Grocycode.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Helpers;
|
||||
|
||||
/**
|
||||
* A class that abstracts grocycode.
|
||||
*
|
||||
* grocycode is a simple, easily serializable format to reference
|
||||
* stuff within grocy. It consists of n (n ≥ 3) double-colon seperated parts:
|
||||
*
|
||||
* 1. The magic `grcy`
|
||||
* 2. A type identifer, must match `[a-z]+` (i.e. only lowercase ascii, minimum length 1 character)
|
||||
* 3. An object id
|
||||
* 4. Any number of further data fields, double-colon seperated.
|
||||
*
|
||||
* @author Katharina Bogad <katharina@hacked.xyz>
|
||||
*/
|
||||
class Grocycode
|
||||
{
|
||||
public const PRODUCT = 'p';
|
||||
|
||||
public const BATTERY = 'b';
|
||||
|
||||
public const CHORE = 'c';
|
||||
|
||||
public const MAGIC = 'grcy';
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the Grocycode class.
|
||||
*
|
||||
* Because php doesn't support overloading, this is a proxy
|
||||
* to either setFromCode($code) or setFromData($type, $id, $extra_data = []).
|
||||
*/
|
||||
public function __construct(...$args)
|
||||
{
|
||||
$argc = count($args);
|
||||
if ($argc == 1)
|
||||
{
|
||||
$this->setFromCode($args[0]);
|
||||
return;
|
||||
}
|
||||
elseif ($argc == 2 || $argc == 3)
|
||||
{
|
||||
if ($argc == 2)
|
||||
{
|
||||
$args[] = [];
|
||||
}
|
||||
$this->setFromData($args[0], $args[1], $args[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \Exception('No suitable overload found.');
|
||||
}
|
||||
|
||||
/**
|
||||
* An array that registers all valid grocycode types. Register yours here by appending to this array.
|
||||
*/
|
||||
public static $Items = [self::PRODUCT, self::BATTERY, self::CHORE];
|
||||
|
||||
private $type;
|
||||
|
||||
private $id;
|
||||
|
||||
private $extra_data = [];
|
||||
|
||||
/**
|
||||
* Validates a grocycode.
|
||||
*
|
||||
* Returns true, if a supplied $code is a valid grocycode, false otherwise.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function Validate(string $code)
|
||||
{
|
||||
try
|
||||
{
|
||||
$gc = new self($code);
|
||||
return true;
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetId()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function GetExtraData()
|
||||
{
|
||||
return $this->extra_data;
|
||||
}
|
||||
|
||||
public function GetType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
$arr = array_merge([self::MAGIC, $this->type, $this->id], $this->extra_data);
|
||||
|
||||
return implode(':', $arr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a grocycode.
|
||||
*/
|
||||
private function setFromCode($code)
|
||||
{
|
||||
$parts = array_reverse(explode(':', $barcode));
|
||||
if (array_pop($parts) != self::MAGIC)
|
||||
{
|
||||
throw new \Exception('Not a grocycode');
|
||||
}
|
||||
|
||||
if (!in_array($this->type = array_pop($parts), self::$Items))
|
||||
{
|
||||
throw new \Exception('Unknown grocycode type');
|
||||
}
|
||||
|
||||
$this->id = array_pop($parts);
|
||||
$this->extra_data = array_reverse($parse);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a grocycode from data.
|
||||
*/
|
||||
private function setFromData($type, $id, $extra_data = [])
|
||||
{
|
||||
if (!is_array($extra_data))
|
||||
{
|
||||
throw new \Exception('Extra data must be array of string');
|
||||
}
|
||||
if (!in_array($type, self::$Items))
|
||||
{
|
||||
throw new \Exception('Unknown grocycode type');
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
$this->id = $id;
|
||||
$this->extra_data = $extra_data;
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@ class ERequirementNotMet extends Exception
|
||||
{
|
||||
}
|
||||
|
||||
const REQUIRED_PHP_EXTENSIONS = ['fileinfo', 'pdo_sqlite', 'gd', 'ctype'];
|
||||
const REQUIRED_PHP_EXTENSIONS = ['fileinfo', 'pdo_sqlite', 'gd', 'ctype', 'json', 'intl', 'zlib'];
|
||||
const REQUIRED_SQLITE_VERSION = '3.9.0';
|
||||
|
||||
class PrerequisiteChecker
|
||||
|
@@ -4,6 +4,18 @@ namespace Grocy\Helpers;
|
||||
|
||||
class UrlManager
|
||||
{
|
||||
public function __construct(string $basePath)
|
||||
{
|
||||
if ($basePath === '/')
|
||||
{
|
||||
$this->BasePath = $this->GetBaseUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->BasePath = $basePath;
|
||||
}
|
||||
}
|
||||
|
||||
protected $BasePath;
|
||||
|
||||
public function ConstructUrl($relativePath, $isResource = false)
|
||||
@@ -18,18 +30,6 @@ class UrlManager
|
||||
}
|
||||
}
|
||||
|
||||
public function __construct(string $basePath)
|
||||
{
|
||||
if ($basePath === '/')
|
||||
{
|
||||
$this->BasePath = $this->GetBaseUrl();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->BasePath = $basePath;
|
||||
}
|
||||
}
|
||||
|
||||
private function GetBaseUrl()
|
||||
{
|
||||
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strpos($_SERVER['HTTP_X_FORWARDED_PROTO'], 'https') !== false)
|
||||
|
48
helpers/WebhookRunner.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Grocy\Helpers;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ExceptionRequestException;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class WebhookRunner
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->client = new Client(['timeout' => 2.0]);
|
||||
}
|
||||
|
||||
private $client;
|
||||
|
||||
public function run($url, $args, $json = false)
|
||||
{
|
||||
$reqArgs = [];
|
||||
if ($json)
|
||||
{
|
||||
$reqArgs = ['json' => $args];
|
||||
}
|
||||
else
|
||||
{
|
||||
$reqArgs = ['form_params' => $args];
|
||||
}
|
||||
try
|
||||
{
|
||||
file_put_contents('php://stderr', 'Running Webhook: ' . $url . "\n" . print_r($reqArgs, true));
|
||||
|
||||
$this->client->request('POST', $url, $reqArgs);
|
||||
}
|
||||
catch (RequestException $e)
|
||||
{
|
||||
file_put_contents('php://stderr', 'Webhook failed: ' . $url . "\n" . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function runAll($urls, $args)
|
||||
{
|
||||
foreach ($urls as $url)
|
||||
{
|
||||
$this->run($url, $args);
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,8 +4,7 @@ function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue)
|
||||
{
|
||||
foreach ($array as $object)
|
||||
{
|
||||
if ($object->{$propertyName}
|
||||
== $propertyValue)
|
||||
if ($object->{$propertyName} == $propertyValue)
|
||||
{
|
||||
return $object;
|
||||
}
|
||||
@@ -17,37 +16,28 @@ function FindObjectInArrayByPropertyValue($array, $propertyName, $propertyValue)
|
||||
function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyValue, $operator = '==')
|
||||
{
|
||||
$returnArray = [];
|
||||
|
||||
foreach ($array as $object)
|
||||
{
|
||||
switch ($operator)
|
||||
{
|
||||
case '==':
|
||||
|
||||
if ($object->{$propertyName}
|
||||
== $propertyValue)
|
||||
if ($object->{$propertyName} == $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
|
||||
break;
|
||||
case '>':
|
||||
|
||||
if ($object->{$propertyName}
|
||||
> $propertyValue)
|
||||
if ($object->{$propertyName} > $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
|
||||
break;
|
||||
case '<':
|
||||
|
||||
if ($object->{$propertyName}
|
||||
< $propertyValue)
|
||||
if ($object->{$propertyName} < $propertyValue)
|
||||
{
|
||||
$returnArray[] = $object;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -58,7 +48,6 @@ function FindAllObjectsInArrayByPropertyValue($array, $propertyName, $propertyVa
|
||||
function FindAllItemsInArrayByValue($array, $value, $operator = '==')
|
||||
{
|
||||
$returnArray = [];
|
||||
|
||||
foreach ($array as $item)
|
||||
{
|
||||
switch ($operator)
|
||||
@@ -69,7 +58,6 @@ function FindAllItemsInArrayByValue($array, $value, $operator = '==')
|
||||
{
|
||||
$returnArray[] = $item;
|
||||
}
|
||||
|
||||
break;
|
||||
case '>':
|
||||
|
||||
@@ -77,7 +65,6 @@ function FindAllItemsInArrayByValue($array, $value, $operator = '==')
|
||||
{
|
||||
$returnArray[] = $item;
|
||||
}
|
||||
|
||||
break;
|
||||
case '<':
|
||||
|
||||
@@ -85,7 +72,6 @@ function FindAllItemsInArrayByValue($array, $value, $operator = '==')
|
||||
{
|
||||
$returnArray[] = $item;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +82,6 @@ function FindAllItemsInArrayByValue($array, $value, $operator = '==')
|
||||
function SumArrayValue($array, $propertyName)
|
||||
{
|
||||
$sum = 0;
|
||||
|
||||
foreach ($array as $object)
|
||||
{
|
||||
$sum += floatval($object->{$propertyName});
|
||||
@@ -124,7 +109,6 @@ function GetClassConstants($className, $prefix = null)
|
||||
function RandomString($length, $allowedChars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
|
||||
{
|
||||
$randomString = '';
|
||||
|
||||
for ($i = 0; $i < $length; $i++)
|
||||
{
|
||||
$randomString .= $allowedChars[rand(0, strlen($allowedChars) - 1)];
|
||||
@@ -156,6 +140,11 @@ function BoolToString(bool $bool)
|
||||
return $bool ? 'true' : 'false';
|
||||
}
|
||||
|
||||
function BoolToInt(bool $bool)
|
||||
{
|
||||
return $bool ? 1 : 0;
|
||||
}
|
||||
|
||||
function ExternalSettingValue(string $value)
|
||||
{
|
||||
$tvalue = rtrim($value, "\r\n");
|
||||
@@ -185,7 +174,8 @@ function Setting(string $name, $value)
|
||||
define('GROCY_' . $name, ExternalSettingValue(file_get_contents($settingOverrideFile)));
|
||||
}
|
||||
elseif (getenv('GROCY_' . $name) !== false)
|
||||
{ // An environment variable with the same name and prefix GROCY_ overwrites the given setting
|
||||
{
|
||||
// An environment variable with the same name and prefix GROCY_ overwrites the given setting
|
||||
define('GROCY_' . $name, ExternalSettingValue(getenv('GROCY_' . $name)));
|
||||
}
|
||||
else
|
||||
|
@@ -400,3 +400,12 @@ msgstr ""
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finsky"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
||||
# Jarda Tesar <intossh@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-31 19:11+0000\n"
|
||||
"Last-Translator: Radim Kabeláč <radim.ekk@gmail.com>, 2020\n"
|
||||
"Last-Translator: Jarda Tesar <intossh@gmail.com>, 2021\n"
|
||||
"Language-Team: Czech (https://www.transifex.com/grocy/teams/93189/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -107,16 +108,16 @@ msgstr "Čínština (Tradiční)"
|
||||
|
||||
# Chinese (China)
|
||||
msgid "zh_CN"
|
||||
msgstr ""
|
||||
msgstr "Čínština (Zjednodušená)"
|
||||
|
||||
# Hebrew (Israel)
|
||||
msgid "he_IL"
|
||||
msgstr ""
|
||||
msgstr "Hebrejština"
|
||||
|
||||
# Tamil
|
||||
msgid "ta"
|
||||
msgstr ""
|
||||
msgstr "Tamilština"
|
||||
|
||||
# Finnish
|
||||
msgid "fi"
|
||||
msgstr ""
|
||||
msgstr "Finština"
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
||||
# Jarda Tesar <intossh@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-29 16:33+0000\n"
|
||||
"Last-Translator: Radim Kabeláč <radim.ekk@gmail.com>, 2020\n"
|
||||
"Last-Translator: Jarda Tesar <intossh@gmail.com>, 2021\n"
|
||||
"Language-Team: Czech (https://www.transifex.com/grocy/teams/93189/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -43,11 +44,11 @@ msgstr "BATERIE_VRACENI_NABIJECI_CYKLUS"
|
||||
|
||||
# Track charge cycle
|
||||
msgid "BATTERIES_TRACK_CHARGE_CYCLE"
|
||||
msgstr ""
|
||||
msgstr "BATERIE_SLEDOVANI_NABIJECI_CYKLUS"
|
||||
|
||||
# Track execution
|
||||
msgid "CHORE_TRACK_EXECUTION"
|
||||
msgstr ""
|
||||
msgstr "POVINNOST_SLEDOVANI_VYKONANI"
|
||||
|
||||
# Undo execution
|
||||
msgid "CHORE_UNDO_EXECUTION"
|
||||
|
@@ -8,6 +8,7 @@
|
||||
# Adam Kroupa <mavi222@seznam.cz>, 2020
|
||||
# Radim Kabeláč <radim.ekk@gmail.com>, 2020
|
||||
# Jaroslav Lichtblau <jlichtblau@seznam.cz>, 2020
|
||||
# Jarda Tesar <intossh@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -15,7 +16,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Jaroslav Lichtblau <jlichtblau@seznam.cz>, 2020\n"
|
||||
"Last-Translator: Jarda Tesar <intossh@gmail.com>, 2021\n"
|
||||
"Language-Team: Czech (https://www.transifex.com/grocy/teams/93189/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -352,8 +353,8 @@ msgstr "Opravdu chcete smazat obchod \"%s\"?"
|
||||
msgid "Manage API keys"
|
||||
msgstr "Spravovat API klíče"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "REST API & dokumentace datových modelů"
|
||||
msgid "REST API browser"
|
||||
msgstr ""
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "API klíče"
|
||||
@@ -655,6 +656,9 @@ msgid ""
|
||||
"Are you sure to consume all ingredients needed by recipe \"%s\" (ingredients"
|
||||
" marked with \"only check if any amount is in stock\" will be ignored)?"
|
||||
msgstr ""
|
||||
"Opravdu si přejete spotřebovat všechny suroviny potřebné v receptu \"%s\" "
|
||||
"(suroviny označené \"Zkontrolovat pouze zda je v zásobě jakékoliv množství\""
|
||||
" budou ignorované)?"
|
||||
|
||||
msgid "Removed all ingredients of recipe \"%s\" from stock"
|
||||
msgstr "Odebrány všechny suroviny z receptu \"%s\" ze zásob"
|
||||
@@ -896,7 +900,7 @@ msgid "Add all list items to stock"
|
||||
msgstr "Přidat všechny položky seznamu do zásob"
|
||||
|
||||
msgid "Add this item to stock"
|
||||
msgstr ""
|
||||
msgstr "Přidat tuto položku do zásob"
|
||||
|
||||
msgid "Adding shopping list item %1$s of %2$s"
|
||||
msgstr "Přidána položka nákupního seznamu %1$s z %2$s"
|
||||
@@ -1975,7 +1979,7 @@ msgid "Save & continue to add quantity unit conversions & barcodes"
|
||||
msgstr "Uložit a pokračovat do přidání měrných jednotek a čárových kódů"
|
||||
|
||||
msgid "Save & return to products"
|
||||
msgstr "Uložit a pokračovat v editaci"
|
||||
msgstr "Uložit a vrátit se do produktů"
|
||||
|
||||
msgid "Save & continue to add conversions"
|
||||
msgstr "Uložit a pokračovat do přidání konverzí"
|
||||
@@ -2106,7 +2110,8 @@ msgstr "Výchozí počet dní spotřeby"
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default due days after opened"
|
||||
@@ -2315,3 +2320,183 @@ msgstr "Nastavení tisku"
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr "Je vyžadován produkt nebo poznámka"
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Single label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr ""
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Printing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Product description"
|
||||
msgstr ""
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
msgstr[3] ""
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[2] ""
|
||||
msgstr[3] ""
|
||||
|
||||
msgid "Display product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Troels Siggaard <troels@siggaard.com>, 2019
|
||||
# klavslund <klavslund@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-09-17 10:45+0000\n"
|
||||
"Last-Translator: Troels Siggaard <troels@siggaard.com>, 2019\n"
|
||||
"Last-Translator: klavslund <klavslund@gmail.com>, 2021\n"
|
||||
"Language-Team: Danish (https://www.transifex.com/grocy/teams/93189/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -21,7 +22,7 @@ msgid "no-assignment"
|
||||
msgstr "ingen-tildeling"
|
||||
|
||||
msgid "who-least-did-first"
|
||||
msgstr "hvem-mindst-gjorde-først"
|
||||
msgstr "hvem-gjorde-mindst-først"
|
||||
|
||||
msgid "random"
|
||||
msgstr "tilfældig"
|
||||
|
@@ -5,6 +5,7 @@
|
||||
# Rasmus Bojsen <rasmus@bojsen.cn>, 2019
|
||||
# Brian Moos Lindberg <brian@blueeel.dk>, 2019
|
||||
# Mihai Marinescu <mihai@marinescu.dk>, 2020
|
||||
# klavslund <klavslund@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -12,7 +13,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Mihai Marinescu <mihai@marinescu.dk>, 2020\n"
|
||||
"Last-Translator: klavslund <klavslund@gmail.com>, 2021\n"
|
||||
"Language-Team: Danish (https://www.transifex.com/grocy/teams/93189/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -376,13 +377,22 @@ msgid "Korean"
|
||||
msgstr "Koreansk"
|
||||
|
||||
msgid "Chinese (China)"
|
||||
msgstr ""
|
||||
msgstr "Kinesisk"
|
||||
|
||||
msgid "Hebrew (Israel)"
|
||||
msgstr ""
|
||||
msgstr "Hebraisk"
|
||||
|
||||
msgid "Tamil"
|
||||
msgstr ""
|
||||
msgstr "Tamilsk"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finsk"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
122
localization/da/locales.po
Normal file
@@ -0,0 +1,122 @@
|
||||
#
|
||||
# Translators:
|
||||
# klavslund <klavslund@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-31 19:11+0000\n"
|
||||
"Last-Translator: klavslund <klavslund@gmail.com>, 2021\n"
|
||||
"Language-Team: Danish (https://www.transifex.com/grocy/teams/93189/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: da\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Domain: grocy/locales\n"
|
||||
|
||||
# Czech
|
||||
msgid "cs"
|
||||
msgstr "cs"
|
||||
|
||||
# Danish
|
||||
msgid "da"
|
||||
msgstr "da"
|
||||
|
||||
# German
|
||||
msgid "de"
|
||||
msgstr "de"
|
||||
|
||||
# Greek
|
||||
msgid "el_GR"
|
||||
msgstr "el_GR"
|
||||
|
||||
# English
|
||||
msgid "en"
|
||||
msgstr "en"
|
||||
|
||||
# English (Great Britain)
|
||||
msgid "en_GB"
|
||||
msgstr "en_GB"
|
||||
|
||||
# Spanish
|
||||
msgid "es"
|
||||
msgstr "es"
|
||||
|
||||
# French
|
||||
msgid "fr"
|
||||
msgstr "fr"
|
||||
|
||||
# Hungarian
|
||||
msgid "hu"
|
||||
msgstr "hu"
|
||||
|
||||
# Italian
|
||||
msgid "it"
|
||||
msgstr "it"
|
||||
|
||||
# Japanese
|
||||
msgid "ja"
|
||||
msgstr "ja"
|
||||
|
||||
# Korean
|
||||
msgid "ko_KR"
|
||||
msgstr "ko_KR"
|
||||
|
||||
# Dutch
|
||||
msgid "nl"
|
||||
msgstr "nl"
|
||||
|
||||
# Norwegian
|
||||
msgid "no"
|
||||
msgstr "no"
|
||||
|
||||
# Polish
|
||||
msgid "pl"
|
||||
msgstr "pl"
|
||||
|
||||
# Portuguese (Brazil)
|
||||
msgid "pt_BR"
|
||||
msgstr "pt_BR"
|
||||
|
||||
# Portuguese (Portugal)
|
||||
msgid "pt_PT"
|
||||
msgstr "pt_PT"
|
||||
|
||||
# Russian
|
||||
msgid "ru"
|
||||
msgstr "ru"
|
||||
|
||||
# Slovak
|
||||
msgid "sk_SK"
|
||||
msgstr "sk_SK"
|
||||
|
||||
# Swedish
|
||||
msgid "sv_SE"
|
||||
msgstr "sv_SE"
|
||||
|
||||
# Turkish
|
||||
msgid "tr"
|
||||
msgstr "tr"
|
||||
|
||||
# Chinese (Taiwan)
|
||||
msgid "zh_TW"
|
||||
msgstr "zh_TW"
|
||||
|
||||
# Chinese (China)
|
||||
msgid "zh_CN"
|
||||
msgstr "zh_CN"
|
||||
|
||||
# Hebrew (Israel)
|
||||
msgid "he_IL"
|
||||
msgstr "he_IL"
|
||||
|
||||
# Tamil
|
||||
msgid "ta"
|
||||
msgstr "ta"
|
||||
|
||||
# Finnish
|
||||
msgid "fi"
|
||||
msgstr "fi"
|
139
localization/da/permissions.po
Normal file
@@ -0,0 +1,139 @@
|
||||
#
|
||||
# Translators:
|
||||
# Mihai Marinescu <mihai@marinescu.dk>, 2020
|
||||
# klavslund <klavslund@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-29 16:33+0000\n"
|
||||
"Last-Translator: klavslund <klavslund@gmail.com>, 2021\n"
|
||||
"Language-Team: Danish (https://www.transifex.com/grocy/teams/93189/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: da\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Domain: grocy/permissions\n"
|
||||
|
||||
# All permissions
|
||||
msgid "ADMIN"
|
||||
msgstr "ADMIN"
|
||||
|
||||
# Create users
|
||||
msgid "USERS_CREATE"
|
||||
msgstr "USERS_CREATE"
|
||||
|
||||
# Edit users (including passwords)
|
||||
msgid "USERS_EDIT"
|
||||
msgstr "USERS_EDIT"
|
||||
|
||||
# Show users
|
||||
msgid "USERS_READ"
|
||||
msgstr "USERS_READ"
|
||||
|
||||
# Edit own user data / change own password
|
||||
msgid "USERS_EDIT_SELF"
|
||||
msgstr "USERS_EDIT_SELF"
|
||||
|
||||
# Undo charge cycle
|
||||
msgid "BATTERIES_UNDO_CHARGE_CYCLE"
|
||||
msgstr "BATTERIES_UNDO_CHARGE_CYCLE"
|
||||
|
||||
# Track charge cycle
|
||||
msgid "BATTERIES_TRACK_CHARGE_CYCLE"
|
||||
msgstr "BATTERIES_TRACK_CHARGE_CYCLE"
|
||||
|
||||
# Track execution
|
||||
msgid "CHORE_TRACK_EXECUTION"
|
||||
msgstr "CHORE_TRACK_EXECUTION"
|
||||
|
||||
# Undo execution
|
||||
msgid "CHORE_UNDO_EXECUTION"
|
||||
msgstr "CHORE_UNDO_EXECUTION"
|
||||
|
||||
# Edit master data
|
||||
msgid "MASTER_DATA_EDIT"
|
||||
msgstr "MASTER_DATA_EDIT"
|
||||
|
||||
# Undo execution
|
||||
msgid "TASKS_UNDO_EXECUTION"
|
||||
msgstr "TASKS_UNDO_EXECUTION"
|
||||
|
||||
# Mark completed
|
||||
msgid "TASKS_MARK_COMPLETED"
|
||||
msgstr "TASKS_MARK_COMPLETED"
|
||||
|
||||
# Edit stock entries
|
||||
msgid "STOCK_EDIT"
|
||||
msgstr "STOCK_EDIT"
|
||||
|
||||
# Transfer
|
||||
msgid "STOCK_TRANSFER"
|
||||
msgstr "STOCK_TRANSFER"
|
||||
|
||||
# Inventory
|
||||
msgid "STOCK_INVENTORY"
|
||||
msgstr "STOCK_INVENTORY"
|
||||
|
||||
# Consume
|
||||
msgid "STOCK_CONSUME"
|
||||
msgstr "STOCK_CONSUME"
|
||||
|
||||
# Open products
|
||||
msgid "STOCK_OPEN"
|
||||
msgstr "STOCK_OPEN"
|
||||
|
||||
# Purchase
|
||||
msgid "STOCK_PURCHASE"
|
||||
msgstr "STOCK_PURCHASE"
|
||||
|
||||
# Add items
|
||||
msgid "SHOPPINGLIST_ITEMS_ADD"
|
||||
msgstr "SHOPPINGLIST_ITEMS_ADD"
|
||||
|
||||
# Remove items
|
||||
msgid "SHOPPINGLIST_ITEMS_DELETE"
|
||||
msgstr "SHOPPINGLIST_ITEMS_DELETE"
|
||||
|
||||
# User management
|
||||
msgid "USERS"
|
||||
msgstr "BRUGERE"
|
||||
|
||||
# Stock
|
||||
msgid "STOCK"
|
||||
msgstr "BEHOLDNING"
|
||||
|
||||
# Shopping list
|
||||
msgid "SHOPPINGLIST"
|
||||
msgstr "INDKØBSLISTE"
|
||||
|
||||
# Chores
|
||||
msgid "CHORES"
|
||||
msgstr "GØREMÅL"
|
||||
|
||||
# Batteries
|
||||
msgid "BATTERIES"
|
||||
msgstr "BATTERIER"
|
||||
|
||||
# Tasks
|
||||
msgid "TASKS"
|
||||
msgstr "OPGAVER"
|
||||
|
||||
# Recipes
|
||||
msgid "RECIPES"
|
||||
msgstr "OPSKRIFTER"
|
||||
|
||||
# Equipment
|
||||
msgid "EQUIPMENT"
|
||||
msgstr "UDSTYR"
|
||||
|
||||
# Calendar
|
||||
msgid "CALENDAR"
|
||||
msgstr "KALENDER"
|
||||
|
||||
# Meal plan
|
||||
msgid "RECIPES_MEALPLAN"
|
||||
msgstr "RECIPES_MEALPLAN"
|
@@ -2,6 +2,7 @@
|
||||
# Translators:
|
||||
# Brian Moos Lindberg <brian@blueeel.dk>, 2019
|
||||
# Mihai Marinescu <mihai@marinescu.dk>, 2020
|
||||
# klavslund <klavslund@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -9,7 +10,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:43+0000\n"
|
||||
"Last-Translator: Mihai Marinescu <mihai@marinescu.dk>, 2020\n"
|
||||
"Last-Translator: klavslund <klavslund@gmail.com>, 2021\n"
|
||||
"Language-Team: Danish (https://www.transifex.com/grocy/teams/93189/da/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -60,7 +61,7 @@ msgstr "link"
|
||||
|
||||
# Link (with title)
|
||||
msgid "link-with-title"
|
||||
msgstr ""
|
||||
msgstr "link-med-overskrift"
|
||||
|
||||
# File
|
||||
msgid "file"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-09-17 10:45+0000\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2019\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2021\n"
|
||||
"Language-Team: German (https://www.transifex.com/grocy/teams/93189/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2019\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2021\n"
|
||||
"Language-Team: German (https://www.transifex.com/grocy/teams/93189/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2020
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2020\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2021\n"
|
||||
"Language-Team: German (https://www.transifex.com/grocy/teams/93189/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -382,3 +382,12 @@ msgstr "Tamil"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finnisch"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr "Frühstück"
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr "Mittagessen"
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr "Abendessen"
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2020
|
||||
# @RubenKelevra <ruben@freifunk-nrw.de>, 2021
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-29 16:33+0000\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2020\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2021\n"
|
||||
"Language-Team: German (https://www.transifex.com/grocy/teams/93189/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#
|
||||
# Translators:
|
||||
# Hagen Tasche <github@fvbor.de>, 2020
|
||||
# Luca RHK <luca@rhk-in.de>, 2020
|
||||
# Tobias Wolter <mumpfpuffel@gmail.com>, 2020
|
||||
# @RubenKelevra <ruben@freifunk-nrw.de>, 2021
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2021
|
||||
#
|
||||
msgid ""
|
||||
@@ -337,8 +337,8 @@ msgstr "Geschäft \"%s\" wirklich löschen?"
|
||||
msgid "Manage API keys"
|
||||
msgstr "API-Schlüssel verwalten"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "REST-API & Datenmodell Dokumentation"
|
||||
msgid "REST API browser"
|
||||
msgstr "REST API Browser"
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "API-Schlüssel"
|
||||
@@ -1977,10 +1977,10 @@ msgid "Common"
|
||||
msgstr "Allgemein"
|
||||
|
||||
msgid "Decimal places allowed for amounts"
|
||||
msgstr "Erlaubte Dezimalstellen für Mengen"
|
||||
msgstr "Erlaubte Nachkommastellen für Mengen"
|
||||
|
||||
msgid "Decimal places allowed for prices"
|
||||
msgstr "Erlaubte Dezimalstellen für Preise"
|
||||
msgstr "Erlaubte Nachkommastellen für Preise"
|
||||
|
||||
msgid "Stock entries for this product"
|
||||
msgstr "Bestandseinträge für dieses Produkt"
|
||||
@@ -2135,11 +2135,13 @@ msgstr "Standard-Fälligkeitstage"
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
"Wenn dieses Produkt als geöffnet markiert wurde, wird das Fälligkeitsdatum "
|
||||
"durch heute + diese Anzahl von Tagen ersetzt (ein Wert von 0 deaktiviert "
|
||||
"dies) "
|
||||
"durch heute + diese Anzahl von Tagen ersetzt, aber nur, wenn das "
|
||||
"resultierende Datum nicht nach dem ursprünglichen Fälligkeitsdatum liegt "
|
||||
"(ein Wert von 0 deaktiviert dies) "
|
||||
|
||||
msgid "Default due days after opened"
|
||||
msgstr "Standard-Fälligkeitstage nach dem Öffnen"
|
||||
@@ -2374,3 +2376,189 @@ msgstr "Druckoptionen"
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr "Ein Produkt oder eine Notiz ist erforderlich"
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr "grocycode"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "Herunterladen"
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr "%s grocycode herunterladen"
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
"grocycode ist eine eindeutige Referenz zu diesem/dieser %s in dieser grocy-"
|
||||
"Instanz - ausgedruckt kann es wie jeder andere Barcode gescannt werden"
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr "MHD"
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr "Auf Etikettendrucker drucken"
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr "Bestandseintrag-Etikett"
|
||||
|
||||
msgid "No label"
|
||||
msgstr "Kein Etikett"
|
||||
|
||||
msgid "Single label"
|
||||
msgstr "Ein Etikett pro Einkauf"
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr "Ein Etikett pro Einheit"
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr "Erlaube Etikettendruck pro Einheit"
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
"Erlaube Etikettendruck pro Einheit nach Umrechnung - Beispiel: 1 gekaufte "
|
||||
"Packung, die 10 Einheiten hinzufügt, druckt 10 Etiketten"
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr "Fehler bei WebHook-Ausführung"
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr "%s grocycode auf Etikettendrucker drucken"
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr "Bestandseintrag-Etikett in neuem Fenster öffnen"
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr "Thermodrucker"
|
||||
|
||||
msgid "Printing"
|
||||
msgstr "Drucken"
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr "Verbindung zum Drucker wird hergestellt..."
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr "Drucken nicht möglich"
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr "Nur erledigte Einträge"
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr "Nur vorrätige Produkte anzeigen"
|
||||
|
||||
msgid "Product description"
|
||||
msgstr "Produktbeschreibung"
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr "%1$s pro %2$s"
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr "Diesen Eintrag als unerledigt markieren"
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr "Erforderlich"
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr "Erforderliches Benutzerfeld"
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
"Wenn aktiviert, dann muss dieses Feld im Zielformular ausgefüllt werden"
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr "Vorrätige Produkte"
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr "Zeitstempel"
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr "Sollte nicht eingefroren werden"
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
"Wenn aktiviert und wenn dieses Produkt zu einem Gefrier-Standort umgelagert "
|
||||
"(sprich eingefroren) wird, wird eine entsprechende Warnung angezeigt"
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr "Dieses Produkt sollte nicht eingefroren werden"
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr "Alle Einträge vom %s kopieren"
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr "Ein Datum ist erforderlich"
|
||||
|
||||
msgid "Day"
|
||||
msgstr "Tag"
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr "Rezept hinzufügen"
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr "Diesen Tag kopieren"
|
||||
|
||||
msgid "Date range"
|
||||
msgstr "Zeitraum"
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] "%s Monat"
|
||||
msgstr[1] "%s Monate"
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] "%s Jahr"
|
||||
msgstr[1] "%s Jahre"
|
||||
|
||||
msgid "Display product"
|
||||
msgstr "Produkt anzeigen"
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr "Rezept kopieren"
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr "Kopie von %s"
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr "Dezimaltrennzeichen für Preis-Eingabefelder automatisch hinzufügen"
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
"Wenn aktiviert, müssen Preiseingaben immer inkl. Nachkommastellen erfolgen, "
|
||||
"das Dezimaltrennzeichen wird automatisch entsprechend der Anzahl der "
|
||||
"erlaubten Nachkommastellen hinzugefügt"
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr "Bestandseintrag"
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr "Abschnitte konfigurieren"
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr "Speiseplan-Abschnitte"
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr "Speiseplan-Abschnitt erstellen"
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr "Die Abschnitte werden nach dieser Nummer auf dem Speiseplan sortiert"
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr "Speiseplan-Abschnitt bearbeiten"
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr "Speiseplan-Abschnitt \"%s\" wirklich löschen?"
|
||||
|
||||
msgid "Section"
|
||||
msgstr "Abschnitt"
|
||||
|
@@ -377,3 +377,12 @@ msgstr ""
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr ""
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -384,3 +384,12 @@ msgstr ""
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr ""
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -340,8 +340,8 @@ msgstr "Είστε βέβαιοι ότι θα διαγράψετε το κατά
|
||||
msgid "Manage API keys"
|
||||
msgstr "Διαχείριση κλειδιών API"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "REST API & τεκμηρίωση μοντέλου δεδομένων"
|
||||
msgid "REST API browser"
|
||||
msgstr ""
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "Κλειδιά API"
|
||||
@@ -2100,7 +2100,8 @@ msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default due days after opened"
|
||||
@@ -2301,3 +2302,179 @@ msgstr ""
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Single label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr ""
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Printing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Product description"
|
||||
msgstr ""
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Display product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
@@ -3,6 +3,7 @@
|
||||
# Jonathan Adams <jonathan@connockadams.uk>, 2020
|
||||
# duck. <me@duck.me.uk>, 2020
|
||||
# John Coles <john@johncoles.com>, 2020
|
||||
# Chris H <cjh861@outlook.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -10,7 +11,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: John Coles <john@johncoles.com>, 2020\n"
|
||||
"Last-Translator: Chris H <cjh861@outlook.com>, 2021\n"
|
||||
"Language-Team: English (United Kingdom) (https://www.transifex.com/grocy/teams/93189/en_GB/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -374,13 +375,22 @@ msgid "Korean"
|
||||
msgstr "Korean"
|
||||
|
||||
msgid "Chinese (China)"
|
||||
msgstr ""
|
||||
msgstr "Chinese (China)"
|
||||
|
||||
msgid "Hebrew (Israel)"
|
||||
msgstr ""
|
||||
msgstr "Hebrew (Israel)"
|
||||
|
||||
msgid "Tamil"
|
||||
msgstr ""
|
||||
msgstr "Tamil"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finnish"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -334,8 +334,8 @@ msgstr "Are you sure to delete shop \"%s\"?"
|
||||
msgid "Manage API keys"
|
||||
msgstr "Manage API keys"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "REST API & data model documentation"
|
||||
msgid "REST API browser"
|
||||
msgstr ""
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "API keys"
|
||||
@@ -2060,7 +2060,8 @@ msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default due days after opened"
|
||||
@@ -2261,3 +2262,179 @@ msgstr ""
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Single label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr ""
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Printing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Product description"
|
||||
msgstr ""
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Display product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
@@ -119,13 +119,13 @@ msgid "Warranty ends"
|
||||
msgstr "Final de la garantía"
|
||||
|
||||
msgid "TV remote control"
|
||||
msgstr "Control remoto del televisor"
|
||||
msgstr "Mando a distancia de la televisión"
|
||||
|
||||
msgid "Alarm clock"
|
||||
msgstr "Despertador"
|
||||
|
||||
msgid "Heat remote control"
|
||||
msgstr "Control remoto de la calefacción"
|
||||
msgstr "Mando a distancia de la calefacción"
|
||||
|
||||
msgid "Lawn mowed in the garden"
|
||||
msgstr "Cortar el césped del jardín"
|
||||
@@ -387,3 +387,12 @@ msgstr "Tamil"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finés"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -10,6 +10,7 @@
|
||||
# Alan Pucheta <apucheta@protonmail.com>, 2020
|
||||
# Enrique Lapenta <enriquelap20@gmail.com>, 2020
|
||||
# Alberto Martin <ami232@gmail.com>, 2021
|
||||
# Adrián R.G. <adrirgrillo@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -17,7 +18,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Alberto Martin <ami232@gmail.com>, 2021\n"
|
||||
"Last-Translator: Adrián R.G. <adrirgrillo@gmail.com>, 2021\n"
|
||||
"Language-Team: Spanish (https://www.transifex.com/grocy/teams/93189/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -345,8 +346,8 @@ msgstr "¿Está seguro de querer eliminar la tienda \"%s\"?"
|
||||
msgid "Manage API keys"
|
||||
msgstr "Administrar las claves de API"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "Documentación de la API REST y modelo de datos"
|
||||
msgid "REST API browser"
|
||||
msgstr ""
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "Claves de API"
|
||||
@@ -889,7 +890,7 @@ msgid ""
|
||||
"The first item in this list would be picked by the default rule which is "
|
||||
"\"Opened first, then first due first, then first in first out\""
|
||||
msgstr ""
|
||||
"El primer artículo de esta lista será selecionado según la regla "
|
||||
"El primer artículo de esta lista será seleccionado según la regla "
|
||||
"predeterminada, que es \"Abiertos primero, luego el próximo en llegar a su "
|
||||
"fecha límite y luego el que se adquirió primero\""
|
||||
|
||||
@@ -971,7 +972,7 @@ msgid "Uncheck ingredients to not put them on the shopping list"
|
||||
msgstr "Desmarca ingredientes para no añadirlos a la lista de la compra"
|
||||
|
||||
msgid "This is for statistical purposes only"
|
||||
msgstr "Sólo para fines estadísticos"
|
||||
msgstr "Esto es solo para fines estadísticos"
|
||||
|
||||
msgid "You have to select a recipe"
|
||||
msgstr "Debe de seleccionar una receta"
|
||||
@@ -1359,7 +1360,7 @@ msgid "Override for product"
|
||||
msgstr "Conversión particular para el producto"
|
||||
|
||||
msgid "This equals %1$s %2$s"
|
||||
msgstr "Esto es igual a %1$s %2$"
|
||||
msgstr "Esto es igual a %1$s %2$s"
|
||||
|
||||
msgid "Edit QU conversion"
|
||||
msgstr "Modificar la conversión de unidades"
|
||||
@@ -2058,7 +2059,7 @@ msgid ""
|
||||
"This is the default quantity unit used when adding this product to the "
|
||||
"shopping list"
|
||||
msgstr ""
|
||||
"Esta es la unidad de cantidad predeterminada para añadir este producto a la "
|
||||
"Esta es la unidad de cantidad predeterminada al añadir este producto a la "
|
||||
"lista de la compra"
|
||||
|
||||
msgid ""
|
||||
@@ -2078,6 +2079,9 @@ msgid ""
|
||||
"automatically populated (by product and/or barcode defaults), the "
|
||||
"transaction is automatically submitted"
|
||||
msgstr ""
|
||||
"Si está activado, al cambiar/escanear un producto cuyos todos sus campos "
|
||||
"pueden ser rellenados automáticamente (con los valores predeterminados para "
|
||||
"el producto o código de barras), la transacción se realiza automáticamente"
|
||||
|
||||
msgid "Quick consume amount"
|
||||
msgstr "Cantidad de consumo rápido"
|
||||
@@ -2136,11 +2140,9 @@ msgstr "Número predeterminado de días hasta la fecha límite"
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
"Cuando este producto se marque como abierto, la fecha límite será "
|
||||
"reemplazada por la fecha de hoy más este número de días (un valor de 0 "
|
||||
"desactiva esto)"
|
||||
|
||||
msgid "Default due days after opened"
|
||||
msgstr ""
|
||||
@@ -2376,3 +2378,179 @@ msgstr "Opciones de impresión"
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr "Hace falta un producto o una nota"
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Single label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr ""
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Printing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Product description"
|
||||
msgstr ""
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Display product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
@@ -385,3 +385,12 @@ msgstr "Tamili"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Suomi"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -392,3 +392,12 @@ msgstr "Tamoul"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finnois"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -11,7 +11,6 @@
|
||||
# Antonin DESFONTAINES <antonin.desfontaines@outlook.com>, 2019
|
||||
# Adrien Guillement <adrien.guillement@gmail.com>, 2019
|
||||
# Matthias Baumgartner <dersoistargate@gmail.com>, 2019
|
||||
# Zkryvix <angelo.frangione@gmail.com>, 2020
|
||||
# Guillaume RICHARD <giz.richard@gmail.com>, 2020
|
||||
# Bastien SOL <agentcobra57@gmail.com>, 2020
|
||||
# Bruno D'agen <iamlionem@gmail.com>, 2020
|
||||
@@ -22,15 +21,18 @@
|
||||
# S Hugeee <sebsebsebseb007@gmail.com>, 2020
|
||||
# Renaud Martinet <me+github@renaudmarti.net>, 2020
|
||||
# Pierre Dumoulin <dumoulinpierre@icloud.com>, 2020
|
||||
# Michel Baie <tristan@lesbringuier.net>, 2020
|
||||
# Tristan <tristan@lesbringuier.net>, 2020
|
||||
# Jordan COUTON <couton.jordan@gmail.com>, 2020
|
||||
# Juan RODRIGUEZ <juansero29@gmail.com>, 2020
|
||||
# Clément CHABANNE <clementchabanne@gmail.com>, 2020
|
||||
# Daniel Nautré <daniel.nautre@gmail.com>, 2020
|
||||
# patate douce <poubel125@gmail.com>, 2020
|
||||
# nerdinator <florian.dupret@gmail.com>, 2020
|
||||
# C P <anoxy78@gmail.com>, 2020
|
||||
# voslin <web@frugier.net>, 2021
|
||||
# Julien Pidoux <julien@pidoux.me>, 2021
|
||||
# Zorvalt - <zorvalt@protonmail.ch>, 2021
|
||||
# Zkryvix <angelo.frangione@gmail.com>, 2021
|
||||
# patate douce <poubel125@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -38,7 +40,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: voslin <web@frugier.net>, 2021\n"
|
||||
"Last-Translator: patate douce <poubel125@gmail.com>, 2021\n"
|
||||
"Language-Team: French (https://www.transifex.com/grocy/teams/93189/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -120,7 +122,7 @@ msgid "Stores"
|
||||
msgstr "Magasins"
|
||||
|
||||
msgid "Quantity units"
|
||||
msgstr "Formats"
|
||||
msgstr "Unités"
|
||||
|
||||
msgid "Chores"
|
||||
msgstr "Corvées"
|
||||
@@ -150,7 +152,7 @@ msgid "Best before"
|
||||
msgstr "DLUO / DLC"
|
||||
|
||||
msgid "OK"
|
||||
msgstr "Ok"
|
||||
msgstr "OK"
|
||||
|
||||
msgid "Product overview"
|
||||
msgstr "Aperçu du produit"
|
||||
@@ -364,8 +366,8 @@ msgstr "Voulez-vous vraiment supprimer le magasin \"%s\" ?"
|
||||
msgid "Manage API keys"
|
||||
msgstr "Gérer les clefs API"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "Documentation sur l'API REST & le modèle des données"
|
||||
msgid "REST API browser"
|
||||
msgstr ""
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "Clefs API"
|
||||
@@ -894,7 +896,7 @@ msgid "Add all list items to stock"
|
||||
msgstr "Ajouter toute la liste dans le stock"
|
||||
|
||||
msgid "Add this item to stock"
|
||||
msgstr ""
|
||||
msgstr "Ajouter ce produit au stock"
|
||||
|
||||
msgid "Adding shopping list item %1$s of %2$s"
|
||||
msgstr "Ajout :%1$s de %2$s à la liste de courses"
|
||||
@@ -2081,6 +2083,9 @@ msgid ""
|
||||
"automatically populated (by product and/or barcode defaults), the "
|
||||
"transaction is automatically submitted"
|
||||
msgstr ""
|
||||
"Lorsqu'activée, après avoir changé/scanné un produit et si tous les champs "
|
||||
"ont pu être automatiquement remplis (par les valeurs par défaut du produit "
|
||||
"ou code barre), la transaction est envoyée automatiquement"
|
||||
|
||||
msgid "Quick consume amount"
|
||||
msgstr "Quantité consommée par défaut"
|
||||
@@ -2138,11 +2143,9 @@ msgstr "Date de péremption par défaut"
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
"Lorsque ce produit est marqué comme ouvert, la date \"À consommer de "
|
||||
"préférence avant\" sera remplacée par aujourd'hui + le nombre de jours (une "
|
||||
"valeur de 0 désactive ceci)"
|
||||
|
||||
msgid "Default due days after opened"
|
||||
msgstr "Date de péremption après ouverture par défaut"
|
||||
@@ -2372,4 +2375,182 @@ msgid "Print options"
|
||||
msgstr "Options d'impression"
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr "Un produit ou une note est nécessaire"
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr "grocycode"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "Télécharger"
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr "Imprimer sur une imprimante d'étiquette"
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No label"
|
||||
msgstr "Pas d'étiquette"
|
||||
|
||||
msgid "Single label"
|
||||
msgstr "Etiquette unique"
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr "Etiquette par unité"
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr "Permettre l'impression d'étiquette par unité"
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
"Permettre l'impression d'une étiquette par unité (après conversion). 1 achat"
|
||||
" qui ajoute 10 produits imprime 10 étiquettes"
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr "Erreur lors de l'exécution de WebHook"
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Printing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Product description"
|
||||
msgstr ""
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Display product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
@@ -2,7 +2,7 @@
|
||||
# Translators:
|
||||
# Adi Zarko <kapkapon@gmail.com>, 2020
|
||||
# Netanel Lazarovich <natylaza89@gmail.com>, 2020
|
||||
# Yaron Shahrabani <sh.yaron@gmail.com>, 2020
|
||||
# Yaron Shahrabani <sh.yaron@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>, 2020\n"
|
||||
"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>, 2021\n"
|
||||
"Language-Team: Hebrew (Israel) (https://www.transifex.com/grocy/teams/93189/he_IL/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -400,3 +400,12 @@ msgstr "טמילית"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "פינית"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr "ארוחת בוקר"
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr "ארוחת צהריים"
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr "ארוחת ערב"
|
||||
|
@@ -343,8 +343,8 @@ msgstr "למחוק את החנות „%s”?"
|
||||
msgid "Manage API keys"
|
||||
msgstr "ניהול מפתחות API"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "תיעוד דגם נתונים ו־REST API"
|
||||
msgid "REST API browser"
|
||||
msgstr "דפדפן REST API"
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "מפתחות API"
|
||||
@@ -2085,10 +2085,11 @@ msgstr "ימים בתוקף עד כבררת מחדל"
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
"כאשר המוצר הזה סומן כפתור, מועד בתוקף עד יוחלף ביום הנוכחי + כמות כזו של "
|
||||
"ימים (0 משבית את ההתנהגות הזאת)"
|
||||
"כאשר המוצר הזה מסומן כפתוח, תאריך התפוגה יוחלף ביום הנוכחי + כמות כזאת של "
|
||||
"ימים, אך רק אם התאריך שמתקבל אינו מאוחר מתאריך התפוגה המקורי (0 ישבית את זה)"
|
||||
|
||||
msgid "Default due days after opened"
|
||||
msgstr "ימים לתום התוקף לאחר הפתיחה כבררת מחדל"
|
||||
@@ -2313,3 +2314,189 @@ msgstr "אפשרויות הדפסה"
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr "נדרש מוצר או הערה"
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr "קוד grocy"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "הורדה"
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr "הורדת קוד grocy של %s"
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
"קוד grocy הוא ייחוס ייחודי עבור %s בעותק ה־grocy שלך - יש להדפיס אותו על "
|
||||
"תווית ולסרוק אותו כמו כל ברקוד אחד."
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr "פג"
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr "הדפסה במדפסת מדבקות"
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr "תווית רשומת מלאי"
|
||||
|
||||
msgid "No label"
|
||||
msgstr "ללא תווית"
|
||||
|
||||
msgid "Single label"
|
||||
msgstr "תווית בודדה"
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr "תווית לכל יחידה"
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr "לאפשר הדפסת תוויות ליחידה"
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
"לאפשר הדפסה של תווית אחת ליחידה ברכישה (לאחר המרה) - למשל: אריזה אחת שנרכשה "
|
||||
"ומוסיפה 10 יחידות למלאי תוביל להדפסת 10 תוויות"
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr "שגיאה בהפעלת התליית רשת"
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr "הדפסת קוד grocy של %s במדפסת מדבקות"
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr "פתיחת תווית רשומת מלאי בחלון חדש"
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr "מדפסת תרמית"
|
||||
|
||||
msgid "Printing"
|
||||
msgstr "מתבצעת הדפסה"
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr "מתבצעת התחברות למדפסת…"
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr "לא ניתן להדפיס"
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr "רק פריטים שהושלמו"
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr "להציג מוצרים מהמלאי בלבד"
|
||||
|
||||
msgid "Product description"
|
||||
msgstr "תיאור מוצר"
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr "%1$s ל%2$s"
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr "סימון הביטול הזה כלא בוצע"
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr "חובה"
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr "שדה משתמש חובה"
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr "כאשר פעיל, חובה למלא את השדה הזה בטופס היעד"
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr "מוצרים במלאי"
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr "חותמת זמן"
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr "לא אמור להיות קפוא"
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr "כאשר פעיל, בהעברת המוצר הזה להקפאה, תופיע אזהרה"
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr "מוצר זה לא אמור להיות קפוא"
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr "העתקת כל רשומות תכנית הארוחות של %s"
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr "נדרש תאריך"
|
||||
|
||||
msgid "Day"
|
||||
msgstr "יום"
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr "הוספת מתכון"
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr "העתקת היום הזה"
|
||||
|
||||
msgid "Date range"
|
||||
msgstr "טווח תאריכים"
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] "חודש"
|
||||
msgstr[1] "חודשיים"
|
||||
msgstr[2] "%s חודשים"
|
||||
msgstr[3] "%s חודשים"
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] "שנה"
|
||||
msgstr[1] "שנתיים"
|
||||
msgstr[2] "%s שנים"
|
||||
msgstr[3] "%s שנים"
|
||||
|
||||
msgid "Display product"
|
||||
msgstr "הצגת מוצר"
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr "העתקת מתכון"
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr "עותק של %s"
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr "יש להוסיף נקודה עשרונית לקלט של מחיר"
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
"כאשר האפשרות פעילה, עליך תמיד למלא את הערך כולל הספרות אחרי הנקודה, הנקודה "
|
||||
"העשרונית תתווסף אוטומטית בהתאם לכמות המקומות העשרוניים האפשריים."
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr "רשומה במלאי"
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr "הגדרת סעיפים"
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr "סעיפי תכנית ארוחות"
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr "יצירת סעיף תכנית ארוחות"
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr "הסעיפים יסודרו לפי המספר על תכנית הארוחות"
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr "עריכת סעיף תכנית ארוחות"
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr "למחוק את הסעיף „%s” מתכנית הארוחות?"
|
||||
|
||||
msgid "Section"
|
||||
msgstr "סעיף"
|
||||
|
@@ -386,3 +386,12 @@ msgstr "Tamil"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finn"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -385,3 +385,12 @@ msgstr "Tamil"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finlandese"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -4,6 +4,7 @@
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Matteo Piotto <matteo.piotto@welaika.com>, 2019
|
||||
# 42d76af3cd20bc399c7e8a413695959f, 2019
|
||||
# Matteo Piccina <altermatte@gmail.com>, 2021
|
||||
# Antonino Ursino <ninus_@libero.it>, 2021
|
||||
#
|
||||
msgid ""
|
||||
@@ -71,10 +72,10 @@ msgid "Batteries overview"
|
||||
msgstr "Riepilogo delle batterie"
|
||||
|
||||
msgid "Purchase"
|
||||
msgstr "Acquisti"
|
||||
msgstr "Acquista"
|
||||
|
||||
msgid "Consume"
|
||||
msgstr "Consumi"
|
||||
msgstr "Consuma"
|
||||
|
||||
msgid "Inventory"
|
||||
msgstr "Inventario"
|
||||
@@ -338,8 +339,8 @@ msgstr "Sei sicuro di voler eliminare il negozio \"%s\"?"
|
||||
msgid "Manage API keys"
|
||||
msgstr "Gestisci le chiavi API"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "REST API & Documentazione del modello di dati"
|
||||
msgid "REST API browser"
|
||||
msgstr ""
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "Chiavi API"
|
||||
@@ -733,7 +734,7 @@ msgid "Status"
|
||||
msgstr "Stato"
|
||||
|
||||
msgid "Below min. stock amount"
|
||||
msgstr "Sotto min. quantità in dispensa"
|
||||
msgstr "Sotto quantità min. in dispensa"
|
||||
|
||||
msgid "Expiring soon"
|
||||
msgstr "In scadenza a breve"
|
||||
@@ -742,7 +743,7 @@ msgid "Already expired"
|
||||
msgstr "Già scaduto"
|
||||
|
||||
msgid "Due soon"
|
||||
msgstr "Da fare subito"
|
||||
msgstr "In scadenza"
|
||||
|
||||
msgid "Overdue"
|
||||
msgstr "In ritardo"
|
||||
@@ -1615,7 +1616,7 @@ msgstr ""
|
||||
"essere programmata solo ogni %s anni"
|
||||
|
||||
msgid "Transfer"
|
||||
msgstr "Trasferire"
|
||||
msgstr "Trasferisci"
|
||||
|
||||
msgid "From location"
|
||||
msgstr "Dalla posizione"
|
||||
@@ -2077,6 +2078,9 @@ msgid ""
|
||||
"automatically populated (by product and/or barcode defaults), the "
|
||||
"transaction is automatically submitted"
|
||||
msgstr ""
|
||||
"Quando abilitato, dopo aver modificato/scansionato un prodotto e se tutti i "
|
||||
"campi possono essere riempiti automaticamente (per prodotto e/o per codice a"
|
||||
" barre predefiniti), la transazione è inviata automaticamente"
|
||||
|
||||
msgid "Quick consume amount"
|
||||
msgstr "Quantità di consumo rapida"
|
||||
@@ -2137,11 +2141,9 @@ msgstr "Giorni di scadenza predefiniti"
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
"Quando questo prodotto è stato contrassegnato come aperto, la data di "
|
||||
"scadenza verrà sostituita da oggi + questo numero di giorni (un valore di 0 "
|
||||
"lo disabilita)"
|
||||
|
||||
msgid "Default due days after opened"
|
||||
msgstr "Giorni di scadenza predefiniti dopo l'apertura"
|
||||
@@ -2376,3 +2378,182 @@ msgstr "Opzioni di stampa"
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr "È richiesto un prodotto o una nota"
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr "codicegrocy"
|
||||
|
||||
msgid "Download"
|
||||
msgstr "Scarica"
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr "Scad."
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr "Stampa su stampante per etichette"
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr "Etichetta della voce di dispensa"
|
||||
|
||||
msgid "No label"
|
||||
msgstr "Senza etichetta"
|
||||
|
||||
msgid "Single label"
|
||||
msgstr "Etichetta singola"
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr "Etichetta per unità"
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr "Consenti la stampa di etichette per unità"
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
"Consenti la stampa di un'etichetta per unità al momento dell'acquisto (dopo "
|
||||
"la conversione) - ad es. 1 confezione acquistata aggiungendo 10 pezzi in "
|
||||
"dispensa stamperebbe 10 etichette"
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr "Errore durante l'esecuzione di WebHook"
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr "Stampante termica"
|
||||
|
||||
msgid "Printing"
|
||||
msgstr "In stampa"
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr "Connessione alla stampante..."
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr "Impossibile stampare"
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Product description"
|
||||
msgstr ""
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Display product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
@@ -376,3 +376,12 @@ msgstr ""
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr ""
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -2184,3 +2184,71 @@ msgstr ""
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download stock entry grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download product grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this product in your grocy instance - print"
|
||||
" it onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Single label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print product grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print stock entry grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry print label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Printing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr ""
|
||||
|
@@ -374,3 +374,12 @@ msgstr ""
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr ""
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# CW kim <cw2002.kim@gmail.com>, 2020
|
||||
# ks <idaksha@outlook.com>, 2020
|
||||
# 신강수 <idaksha@outlook.com>, 2020
|
||||
# CW kim <cw2002.kim@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: ks <idaksha@outlook.com>, 2020\n"
|
||||
"Last-Translator: CW kim <cw2002.kim@gmail.com>, 2021\n"
|
||||
"Language-Team: Korean (Korea) (https://www.transifex.com/grocy/teams/93189/ko_KR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -325,8 +325,8 @@ msgstr "\"%s\" 저장소를 삭제 하시겠습니까? "
|
||||
msgid "Manage API keys"
|
||||
msgstr "API키 관리"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "REST API 및 데이터 모델 문서"
|
||||
msgid "REST API browser"
|
||||
msgstr ""
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "API 키"
|
||||
@@ -1889,7 +1889,7 @@ msgid "Stock entries for this product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit shopping list"
|
||||
msgstr ""
|
||||
msgstr "구매 목록 수정"
|
||||
|
||||
msgid "Save & continue to add quantity unit conversions & barcodes"
|
||||
msgstr ""
|
||||
@@ -2021,7 +2021,8 @@ msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default due days after opened"
|
||||
@@ -2219,4 +2220,178 @@ msgid "Print options"
|
||||
msgstr ""
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr "제품 또는 메모가 필요합니다."
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Single label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr ""
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Printing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Product description"
|
||||
msgstr ""
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] ""
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] ""
|
||||
|
||||
msgid "Display product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
@@ -393,3 +393,12 @@ msgstr "Tamil"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Fins"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Boding Clockchain <joost_nl@live.nl>, 2020
|
||||
# BodingClockchian <joost_nl@live.nl>, 2020
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -9,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Boding Clockchain <joost_nl@live.nl>, 2020\n"
|
||||
"Last-Translator: BodingClockchian <joost_nl@live.nl>, 2020\n"
|
||||
"Language-Team: Dutch (https://www.transifex.com/grocy/teams/93189/nl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Translators:
|
||||
# Marius Borø <blizzwave@gmail.com>, 2019
|
||||
# Marius Borø <blizzwave@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-09-17 10:45+0000\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2019\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -18,13 +18,13 @@ msgstr ""
|
||||
"X-Domain: grocy/chore_assignment_types\n"
|
||||
|
||||
msgid "no-assignment"
|
||||
msgstr "Ingen tildeling"
|
||||
msgstr "no-assignment"
|
||||
|
||||
msgid "who-least-did-first"
|
||||
msgstr " Hvem gjorde minst først"
|
||||
msgstr "who-least-did-first"
|
||||
|
||||
msgid "random"
|
||||
msgstr "Tilfeldig"
|
||||
msgstr "random"
|
||||
|
||||
msgid "in-alphabetical-order"
|
||||
msgstr "I alfabetisk rekkefølge"
|
||||
msgstr "in-alphabetical-order"
|
||||
|
@@ -1,7 +1,6 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Marius Borø <blizzwave@gmail.com>, 2019
|
||||
# Tor Eirik Trandal <teitrand@hotmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -9,7 +8,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2019\n"
|
||||
"Last-Translator: Tor Eirik Trandal <teitrand@hotmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -19,19 +18,19 @@ msgstr ""
|
||||
"X-Domain: grocy/chore_types\n"
|
||||
|
||||
msgid "manually"
|
||||
msgstr "Manuell"
|
||||
msgstr "manuelt"
|
||||
|
||||
msgid "dynamic-regular"
|
||||
msgstr "Automatisk"
|
||||
msgstr "dynamisk-vanlig"
|
||||
|
||||
msgid "daily"
|
||||
msgstr "Daglig"
|
||||
msgstr "daglig"
|
||||
|
||||
msgid "weekly"
|
||||
msgstr "Ukentlig"
|
||||
msgstr "ukentlig"
|
||||
|
||||
msgid "monthly"
|
||||
msgstr "Månedlig"
|
||||
msgstr "månedlig"
|
||||
|
||||
msgid "yearly"
|
||||
msgstr "årlig"
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Marius Borø <blizzwave@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +9,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Bernd Bestel <bernd@berrnd.de>, 2019\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -27,22 +28,7 @@ msgid "moment_locale"
|
||||
msgstr "nb"
|
||||
|
||||
msgid "datatables_localization"
|
||||
msgstr ""
|
||||
"{\"sEmptyTable\":\"Det finnes ingen data i tabellen\",\"sInfo\":\"_START_ "
|
||||
"fra _END_ til _TOTAL_ skriv\",\"sInfoEmpty\":\"Ingen data "
|
||||
"tilgjengelign\",\"sInfoFiltered\":\"(filtrert fra _MAX_ "
|
||||
"skriv)\",\"sInfoPostFix\":\"\",\"sInfoThousands\":\".\",\"sLengthMenu\":\"_MENU_"
|
||||
" per side\",\"sLoadingRecords\":\"Laster ..\",\"sProcessing\":\"Vennligst "
|
||||
"vent ..\",\"sSearch\":\"Søk\",\"sZeroRecords\":\"Ingen oppføringer "
|
||||
"tilgjengelig\",\"oPaginate\":{\"sFirst\":\"Første\",\"sPrevious\":\"Bakover\",\"sNext\":\"Neste\",\"sLast\":\"Siste\"},\"oAria\":{\"sSortAscending\":\":"
|
||||
" Sortér stigende\",\"sSortDescending\":\": Sortér "
|
||||
"synkende\"},\"select\":{\"rows\":{\"0\":\"klikk på en linje for å "
|
||||
"velge\",\"1\":\"1 linje valgt\",\"_\":\" linger "
|
||||
"valgt\"}},\"buttons\":{\"print\":\"Print\",\"colvis\":\"Søyle\",\"copy\":\"Kopi\",\"copyTitle\":\"Kopier"
|
||||
" til utklippstavlen\",\"copyKeys\":\"Trykk <i>ctrl</i> eller <i>⌘</i> + "
|
||||
"<i>C</i> for å kopiere tabell<br> til utklipptavlen.<br><br>For å avbryte, "
|
||||
"klikke på meldingen eller trykk på ESC.\",\"copySuccess\":{\"1\":\"1 Kolonne"
|
||||
" kopiert\",\"_\":\" kolonne kopiert\"}}}"
|
||||
msgstr "datatables_localization"
|
||||
|
||||
msgid "summernote_locale"
|
||||
msgstr "nb-NO"
|
||||
|
@@ -1,8 +1,8 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Marius Borø <blizzwave@gmail.com>, 2020
|
||||
# Ruben Sperre <ruben@rsperre.net>, 2020
|
||||
# Marius Borø <blizzwave@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -10,7 +10,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Ruben Sperre <ruben@rsperre.net>, 2020\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -330,7 +330,7 @@ msgid "current release"
|
||||
msgstr "Nåværende versjon"
|
||||
|
||||
msgid "not yet released"
|
||||
msgstr "enda ikke gitt ut"
|
||||
msgstr "ikke gitt ut enda"
|
||||
|
||||
msgid "Portuguese (Brazil)"
|
||||
msgstr "Portugisisk (Brasil)"
|
||||
@@ -355,11 +355,11 @@ msgstr "Portugisisk (Portugal)"
|
||||
|
||||
# Use a in your country well known supermarket name
|
||||
msgid "DemoSupermarket1"
|
||||
msgstr "DemoButikk1"
|
||||
msgstr "Rema 1000"
|
||||
|
||||
# Use a in your country well known supermarket name
|
||||
msgid "DemoSupermarket2"
|
||||
msgstr "DemoButikk2"
|
||||
msgstr "Kiwi"
|
||||
|
||||
msgid "Japanese"
|
||||
msgstr "Japansk"
|
||||
@@ -368,19 +368,28 @@ msgid "Chinese (Taiwan)"
|
||||
msgstr "Kinesisk (Taiwan)"
|
||||
|
||||
msgid "Greek"
|
||||
msgstr ""
|
||||
msgstr "Gresk"
|
||||
|
||||
msgid "Korean"
|
||||
msgstr ""
|
||||
msgstr "Koreansk"
|
||||
|
||||
msgid "Chinese (China)"
|
||||
msgstr ""
|
||||
msgstr "Kinesisk (China)"
|
||||
|
||||
msgid "Hebrew (Israel)"
|
||||
msgstr ""
|
||||
msgstr "Hebraisk (Israel)"
|
||||
|
||||
msgid "Tamil"
|
||||
msgstr ""
|
||||
msgstr "Tamilsk"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Finsk"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|
123
localization/no/locales.po
Normal file
@@ -0,0 +1,123 @@
|
||||
#
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2020
|
||||
# Marius Borø <blizzwave@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-31 19:11+0000\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: no\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Domain: grocy/locales\n"
|
||||
|
||||
# Czech
|
||||
msgid "cs"
|
||||
msgstr "cs"
|
||||
|
||||
# Danish
|
||||
msgid "da"
|
||||
msgstr "da"
|
||||
|
||||
# German
|
||||
msgid "de"
|
||||
msgstr "de"
|
||||
|
||||
# Greek
|
||||
msgid "el_GR"
|
||||
msgstr "el_GR"
|
||||
|
||||
# English
|
||||
msgid "en"
|
||||
msgstr "no"
|
||||
|
||||
# English (Great Britain)
|
||||
msgid "en_GB"
|
||||
msgstr "en_GB"
|
||||
|
||||
# Spanish
|
||||
msgid "es"
|
||||
msgstr "es"
|
||||
|
||||
# French
|
||||
msgid "fr"
|
||||
msgstr "fr"
|
||||
|
||||
# Hungarian
|
||||
msgid "hu"
|
||||
msgstr "hu"
|
||||
|
||||
# Italian
|
||||
msgid "it"
|
||||
msgstr "it"
|
||||
|
||||
# Japanese
|
||||
msgid "ja"
|
||||
msgstr "ja"
|
||||
|
||||
# Korean
|
||||
msgid "ko_KR"
|
||||
msgstr "ko_KR"
|
||||
|
||||
# Dutch
|
||||
msgid "nl"
|
||||
msgstr "nl"
|
||||
|
||||
# Norwegian
|
||||
msgid "no"
|
||||
msgstr "no"
|
||||
|
||||
# Polish
|
||||
msgid "pl"
|
||||
msgstr "pl"
|
||||
|
||||
# Portuguese (Brazil)
|
||||
msgid "pt_BR"
|
||||
msgstr "pt_BR"
|
||||
|
||||
# Portuguese (Portugal)
|
||||
msgid "pt_PT"
|
||||
msgstr "pt_PT"
|
||||
|
||||
# Russian
|
||||
msgid "ru"
|
||||
msgstr "ru"
|
||||
|
||||
# Slovak
|
||||
msgid "sk_SK"
|
||||
msgstr "sk_SK"
|
||||
|
||||
# Swedish
|
||||
msgid "sv_SE"
|
||||
msgstr "sv_SE"
|
||||
|
||||
# Turkish
|
||||
msgid "tr"
|
||||
msgstr "tr"
|
||||
|
||||
# Chinese (Taiwan)
|
||||
msgid "zh_TW"
|
||||
msgstr "zh_TW"
|
||||
|
||||
# Chinese (China)
|
||||
msgid "zh_CN"
|
||||
msgstr "zh_CN"
|
||||
|
||||
# Hebrew (Israel)
|
||||
msgid "he_IL"
|
||||
msgstr "he_IL"
|
||||
|
||||
# Tamil
|
||||
msgid "ta"
|
||||
msgstr "ta"
|
||||
|
||||
# Finnish
|
||||
msgid "fi"
|
||||
msgstr "fi"
|
139
localization/no/permissions.po
Normal file
@@ -0,0 +1,139 @@
|
||||
#
|
||||
# Translators:
|
||||
# Tor Eirik Trandal <teitrand@hotmail.com>, 2020
|
||||
# Marius Borø <blizzwave@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2020-08-29 16:33+0000\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: no\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Domain: grocy/permissions\n"
|
||||
|
||||
# All permissions
|
||||
msgid "ADMIN"
|
||||
msgstr "ADMIN"
|
||||
|
||||
# Create users
|
||||
msgid "USERS_CREATE"
|
||||
msgstr "USERS_CREATE"
|
||||
|
||||
# Edit users (including passwords)
|
||||
msgid "USERS_EDIT"
|
||||
msgstr "USERS_EDIT"
|
||||
|
||||
# Show users
|
||||
msgid "USERS_READ"
|
||||
msgstr "USERS_READ"
|
||||
|
||||
# Edit own user data / change own password
|
||||
msgid "USERS_EDIT_SELF"
|
||||
msgstr "USERS_EDIT_SELF"
|
||||
|
||||
# Undo charge cycle
|
||||
msgid "BATTERIES_UNDO_CHARGE_CYCLE"
|
||||
msgstr "BATTERIES_UNDO_CHARGE_CYCLE"
|
||||
|
||||
# Track charge cycle
|
||||
msgid "BATTERIES_TRACK_CHARGE_CYCLE"
|
||||
msgstr "BATTERIES_TRACK_CHARGE_CYCLE"
|
||||
|
||||
# Track execution
|
||||
msgid "CHORE_TRACK_EXECUTION"
|
||||
msgstr "CHORE_TRACK_EXECUTION"
|
||||
|
||||
# Undo execution
|
||||
msgid "CHORE_UNDO_EXECUTION"
|
||||
msgstr "CHORE_TRACK_EXECUTION"
|
||||
|
||||
# Edit master data
|
||||
msgid "MASTER_DATA_EDIT"
|
||||
msgstr "MASTER_DATA_EDIT"
|
||||
|
||||
# Undo execution
|
||||
msgid "TASKS_UNDO_EXECUTION"
|
||||
msgstr "TASKS_UNDO_EXECUTION"
|
||||
|
||||
# Mark completed
|
||||
msgid "TASKS_MARK_COMPLETED"
|
||||
msgstr "TASKS_MARK_COMPLETED"
|
||||
|
||||
# Edit stock entries
|
||||
msgid "STOCK_EDIT"
|
||||
msgstr "STOCK_EDIT"
|
||||
|
||||
# Transfer
|
||||
msgid "STOCK_TRANSFER"
|
||||
msgstr "STOCK_TRANSFER"
|
||||
|
||||
# Inventory
|
||||
msgid "STOCK_INVENTORY"
|
||||
msgstr "STOCK_INVENTORY"
|
||||
|
||||
# Consume
|
||||
msgid "STOCK_CONSUME"
|
||||
msgstr "STOCK_CONSUME"
|
||||
|
||||
# Open products
|
||||
msgid "STOCK_OPEN"
|
||||
msgstr "STOCK_OPEN"
|
||||
|
||||
# Purchase
|
||||
msgid "STOCK_PURCHASE"
|
||||
msgstr "STOCK_PURCHASE"
|
||||
|
||||
# Add items
|
||||
msgid "SHOPPINGLIST_ITEMS_ADD"
|
||||
msgstr "SHOPPINGLIST_ITEMS_ADD"
|
||||
|
||||
# Remove items
|
||||
msgid "SHOPPINGLIST_ITEMS_DELETE"
|
||||
msgstr "SHOPPINGLIST_ITEMS_DELETE"
|
||||
|
||||
# User management
|
||||
msgid "USERS"
|
||||
msgstr "USERS"
|
||||
|
||||
# Stock
|
||||
msgid "STOCK"
|
||||
msgstr "STOCK"
|
||||
|
||||
# Shopping list
|
||||
msgid "SHOPPINGLIST"
|
||||
msgstr "SHOPPINGLIST"
|
||||
|
||||
# Chores
|
||||
msgid "CHORES"
|
||||
msgstr "CHORES"
|
||||
|
||||
# Batteries
|
||||
msgid "BATTERIES"
|
||||
msgstr "BATTERIES"
|
||||
|
||||
# Tasks
|
||||
msgid "TASKS"
|
||||
msgstr "TASKS"
|
||||
|
||||
# Recipes
|
||||
msgid "RECIPES"
|
||||
msgstr "RECIPES"
|
||||
|
||||
# Equipment
|
||||
msgid "EQUIPMENT"
|
||||
msgstr "EQUIPMENT"
|
||||
|
||||
# Calendar
|
||||
msgid "CALENDAR"
|
||||
msgstr "CALENDAR"
|
||||
|
||||
# Meal plan
|
||||
msgid "RECIPES_MEALPLAN"
|
||||
msgstr "RECIPES_MEALPLAN"
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Translators:
|
||||
# Marius Borø <blizzwave@gmail.com>, 2020
|
||||
# Marius Borø <blizzwave@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2020\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -18,28 +18,28 @@ msgstr ""
|
||||
"X-Domain: grocy/stock_transaction_types\n"
|
||||
|
||||
msgid "purchase"
|
||||
msgstr "innkjøp"
|
||||
msgstr "Innkjøp"
|
||||
|
||||
msgid "transfer_from"
|
||||
msgstr "overføre_fra"
|
||||
msgstr "Overført fra"
|
||||
|
||||
msgid "transfer_to"
|
||||
msgstr "overføre_til"
|
||||
msgstr "Overført til"
|
||||
|
||||
msgid "consume"
|
||||
msgstr "forbruk"
|
||||
msgstr "Forbruk"
|
||||
|
||||
msgid "inventory-correction"
|
||||
msgstr "beholdningsantall_korreksjon"
|
||||
msgstr "Beholdningsantall korreksjon"
|
||||
|
||||
msgid "product-opened"
|
||||
msgstr "produkt_åpnet"
|
||||
msgstr "Produkt åpnet"
|
||||
|
||||
msgid "stock-edit-old"
|
||||
msgstr "beholdning_endre_gammel"
|
||||
msgstr "Beholdning gammel endring"
|
||||
|
||||
msgid "stock-edit-new"
|
||||
msgstr "beholdning_endre_ny"
|
||||
msgstr "Beholdning ny endring"
|
||||
|
||||
msgid "self-production"
|
||||
msgstr "egenproduksjon"
|
||||
msgstr "Egenproduksjon"
|
||||
|
@@ -2,9 +2,9 @@
|
||||
# Translators:
|
||||
# Bernd Bestel <bernd@berrnd.de>, 2019
|
||||
# Andreas Henden <chairman2s.ah@gmail.com>, 2019
|
||||
# Marius Borø <blizzwave@gmail.com>, 2020
|
||||
# Ruben Sperre <ruben@rsperre.net>, 2020
|
||||
# Tor Eirik Trandal <teitrand@hotmail.com>, 2020
|
||||
# Marius Borø <blizzwave@gmail.com>, 2021
|
||||
# Tor Eirik Trandal <teitrand@hotmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -12,7 +12,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:42+0000\n"
|
||||
"Last-Translator: Tor Eirik Trandal <teitrand@hotmail.com>, 2020\n"
|
||||
"Last-Translator: Tor Eirik Trandal <teitrand@hotmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -41,13 +41,13 @@ msgstr[1] "%s produkter har gått ut på dato"
|
||||
|
||||
msgid "%s product is overdue"
|
||||
msgid_plural "%s products are overdue"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "%s produkt er forbi best før dato"
|
||||
msgstr[1] "%s produkter er forbi best før dato"
|
||||
|
||||
msgid "%s product is below defined min. stock amount"
|
||||
msgid_plural "%s products are below defined min. stock amount"
|
||||
msgstr[0] "%s produkt er under satt minimum for beholdningen"
|
||||
msgstr[1] "%s produkter er under satt minimum for beholdningen"
|
||||
msgstr[0] "%s produkt er under satt min. for beholdningen"
|
||||
msgstr[1] "%s produkter er under satt min. for beholdningen"
|
||||
|
||||
msgid "Product"
|
||||
msgstr "Produkt"
|
||||
@@ -209,7 +209,7 @@ msgid "Default best before days"
|
||||
msgstr "Forhåndsatt antall dager best før"
|
||||
|
||||
msgid "Default quantity unit purchase"
|
||||
msgstr ""
|
||||
msgstr "Standard forpakning kjøpt"
|
||||
|
||||
msgid "Quantity unit stock"
|
||||
msgstr "Forpakning beholdning"
|
||||
@@ -335,8 +335,8 @@ msgstr "Er du sikker på at du vil slette butikken"
|
||||
msgid "Manage API keys"
|
||||
msgstr "Administrer API-Keys"
|
||||
|
||||
msgid "REST API & data model documentation"
|
||||
msgstr "REST-API & datamodell-dokumentasjon"
|
||||
msgid "REST API browser"
|
||||
msgstr ""
|
||||
|
||||
msgid "API keys"
|
||||
msgstr "API-Keys"
|
||||
@@ -615,12 +615,14 @@ msgid "Quantity unit"
|
||||
msgstr "Forpakning"
|
||||
|
||||
msgid "Only check if any amount is in stock"
|
||||
msgstr ""
|
||||
msgstr "Kun sjekk om noe er i beholdningen"
|
||||
|
||||
msgid ""
|
||||
"Are you sure to consume all ingredients needed by recipe \"%s\" (ingredients"
|
||||
" marked with \"only check if any amount is in stock\" will be ignored)?"
|
||||
msgstr ""
|
||||
"Er du sikker på at du vil konsumere alle ingredienser for oppskrift \"%s\"?\n"
|
||||
"(ingredienser merket med \"kun sjekk on noe er i beholdningen\" vil bli ignorert)"
|
||||
|
||||
msgid "Removed all ingredients of recipe \"%s\" from stock"
|
||||
msgstr "Fjern alle ingredienser for \"%s\" oppskriften fra beholdningen."
|
||||
@@ -650,7 +652,7 @@ msgid "Due"
|
||||
msgstr "Forfall"
|
||||
|
||||
msgid "Assigned to"
|
||||
msgstr " Tildelt til"
|
||||
msgstr " Tildelt"
|
||||
|
||||
msgid "Mark task \"%s\" as completed"
|
||||
msgstr "Merk oppgave \"%s\" som ferdig"
|
||||
@@ -674,7 +676,7 @@ msgid "Edit task"
|
||||
msgstr "Endre oppgave"
|
||||
|
||||
msgid "Are you sure to delete task \"%s\"?"
|
||||
msgstr "Er du sikker du ønsker slette oppgave \"%s\"?"
|
||||
msgstr "Er du sikker du ønsker å slette oppgave \"%s\"?"
|
||||
|
||||
msgid "%s task is due to be done"
|
||||
msgid_plural "%s tasks are due to be done"
|
||||
@@ -776,7 +778,7 @@ msgid "Image of product %s"
|
||||
msgstr "Bilde av produkt %s"
|
||||
|
||||
msgid "Deletion not possible"
|
||||
msgstr ""
|
||||
msgstr "Ikke mulig å slette"
|
||||
|
||||
msgid "Equipment"
|
||||
msgstr "Instruksjonsmanualer"
|
||||
@@ -797,7 +799,7 @@ msgid "Create equipment"
|
||||
msgstr "Opprett instruksjonmanualer for et utstyr"
|
||||
|
||||
msgid "The current file will be deleted on save"
|
||||
msgstr ""
|
||||
msgstr "Nåværende fil vil bli slettet når du lagrer"
|
||||
|
||||
msgid "No picture available"
|
||||
msgstr "Ingen bilde tilgjengelig"
|
||||
@@ -860,7 +862,7 @@ msgid "Add all list items to stock"
|
||||
msgstr "Legg alle produktene i listen til beholdningen"
|
||||
|
||||
msgid "Add this item to stock"
|
||||
msgstr ""
|
||||
msgstr "Legg til dette produktet til i beholdningen"
|
||||
|
||||
msgid "Adding shopping list item %1$s of %2$s"
|
||||
msgstr "Legger til handleliste ting %1$s av %2$s"
|
||||
@@ -872,6 +874,8 @@ msgid ""
|
||||
"The first item in this list would be picked by the default rule which is "
|
||||
"\"Opened first, then first due first, then first in first out\""
|
||||
msgstr ""
|
||||
"Det første produktet i denne listen vil bli valgt i henhold til regel "
|
||||
"\"Åpnet først, kommende utgangsdato først, først inn først ut\" "
|
||||
|
||||
msgid "Mark %1$s of %2$s as open"
|
||||
msgstr "Merk %1$s av %2$s som åpen"
|
||||
@@ -892,7 +896,7 @@ msgid "%s opened"
|
||||
msgstr "%s åpnet"
|
||||
|
||||
msgid "Product due"
|
||||
msgstr ""
|
||||
msgstr "Produkt forfalt"
|
||||
|
||||
msgid "Task due"
|
||||
msgstr "Tidsfrist for oppgave"
|
||||
@@ -1006,7 +1010,7 @@ msgid "Gallery"
|
||||
msgstr "Bildegalleri"
|
||||
|
||||
msgid "The current picture will be deleted on save"
|
||||
msgstr ""
|
||||
msgstr "Nåværende produktbilde vil bli slettet når du lagrer"
|
||||
|
||||
msgid "Journal for this battery"
|
||||
msgstr "Logg for dette batteriet"
|
||||
@@ -1031,6 +1035,8 @@ msgstr "Produkttelling"
|
||||
msgid ""
|
||||
"Type a new product name or barcode and hit TAB or ENTER to start a workflow"
|
||||
msgstr ""
|
||||
"Skriv inn nytt produkt navn eller strekkode, trykk så TAB eller ENTER for å "
|
||||
"starte prosessen"
|
||||
|
||||
msgid ""
|
||||
"This will be used as the default setting when adding this product as a "
|
||||
@@ -1228,7 +1234,7 @@ msgid "Booking has subsequent dependent bookings, undo not possible"
|
||||
msgstr "Registrering har flere registreringer under seg, angre er ikke mulig"
|
||||
|
||||
msgid "per serving"
|
||||
msgstr "pr. servering"
|
||||
msgstr "pr. porsjon"
|
||||
|
||||
msgid "Never"
|
||||
msgstr "Aldri"
|
||||
@@ -1245,7 +1251,7 @@ msgstr ""
|
||||
"fjernet!"
|
||||
|
||||
msgid "Undo task"
|
||||
msgstr ""
|
||||
msgstr "Angre oppgave"
|
||||
|
||||
msgid "Due date rollover"
|
||||
msgstr "Forfallsdato rollover"
|
||||
@@ -1269,13 +1275,13 @@ msgstr "Alle lokasjoner"
|
||||
msgid ""
|
||||
"Here you can print a page per location with the current stock, maybe to hang"
|
||||
" it there and note the consumed things on it"
|
||||
msgstr ""
|
||||
msgstr "Her kan du printe ut beholdningsoversikt basert på plassering"
|
||||
|
||||
msgid "this location"
|
||||
msgstr "kun denne lokasjonen"
|
||||
|
||||
msgid "Consumed amount"
|
||||
msgstr ""
|
||||
msgstr "Forbrukt mengde"
|
||||
|
||||
msgid "Time of printing"
|
||||
msgstr "Tidspunkt for utskrift"
|
||||
@@ -1317,7 +1323,7 @@ msgid "This cannot be equal to %s"
|
||||
msgstr "Dette kan ikke være samme som %s"
|
||||
|
||||
msgid "This means 1 %1$s is the same as %2$s %3$s"
|
||||
msgstr "Dette betyr at 1 %1$s er det samme som %2$s%3$s"
|
||||
msgstr "Dette betyr at 1 %1$s er det samme som %2$s %3$s"
|
||||
|
||||
msgid "QU conversions"
|
||||
msgstr "Forpakningskonvertering"
|
||||
@@ -1329,7 +1335,7 @@ msgid "Override for product"
|
||||
msgstr "Overstyr for product"
|
||||
|
||||
msgid "This equals %1$s %2$s"
|
||||
msgstr ""
|
||||
msgstr "Dette er lik %1$s%2$s"
|
||||
|
||||
msgid "Edit QU conversion"
|
||||
msgstr "Endre forpakningskonvertering"
|
||||
@@ -1521,9 +1527,9 @@ msgid ""
|
||||
"this product, means the sub product will never be \"missing\", only this "
|
||||
"product"
|
||||
msgstr ""
|
||||
"Hvis aktivert vil minimum beholdningsnivå av under produkter bli akkumulert "
|
||||
"inn i dette produktet. Dette betyr at underordnede produktet aldri vil "
|
||||
"\"mangle\", kunne dette produktet."
|
||||
"Hvis aktivert vil minimum beholdningsnivå av underordnede produkter bli "
|
||||
"akkumulert inn i dette produktet. Dette betyr at det underordnede produktet "
|
||||
"aldri vil \"mangle\", kunne dette produktet."
|
||||
|
||||
msgid "Are you sure to remove this conversion?"
|
||||
msgstr "Er du sikker på at du ønsker å fjerne denne konverteringen?"
|
||||
@@ -1597,7 +1603,7 @@ msgid "There are no units available at this location"
|
||||
msgstr "Det er ingen enheter tilgjengelig på denne lokasjonen"
|
||||
|
||||
msgid "Amount: %1$s; Due on %2$s; Bought on %3$s"
|
||||
msgstr ""
|
||||
msgstr "Mengde: %1$s; Best før %2$s; Kjøpt %3$s"
|
||||
|
||||
msgid "Transfered %1$s of %2$s from %3$s to %4$s"
|
||||
msgstr "Flyttet %1$s %2$s fra %3$s til %4$s"
|
||||
@@ -1643,6 +1649,8 @@ msgid ""
|
||||
"When a product is selected, one unit (per serving in stock quantity unit) "
|
||||
"will be added to stock on consuming this recipe"
|
||||
msgstr ""
|
||||
"Når et produkt er valgt vil en enhet (per porsjon i beholdningsantall) bli "
|
||||
"lagt til beholdningen når denne oppskriften bli konsumert"
|
||||
|
||||
msgid "Produces product"
|
||||
msgstr "Lager produkt"
|
||||
@@ -1790,7 +1798,7 @@ msgid "means %1$s per %2$s"
|
||||
msgstr "betyr %1$s per %2$s"
|
||||
|
||||
msgid "Create inverse QU conversion"
|
||||
msgstr "Lager invertert QU konvertering"
|
||||
msgstr "Opprett invertert forpaknings konvertering"
|
||||
|
||||
msgid "Create recipe"
|
||||
msgstr "Lag oppskrift"
|
||||
@@ -1806,7 +1814,7 @@ msgid "Save & return to recipes"
|
||||
msgstr "Lagre & returner til oppskrifter"
|
||||
|
||||
msgid "Stock value"
|
||||
msgstr ""
|
||||
msgstr "Beholdningsverdi"
|
||||
|
||||
msgid "Average price"
|
||||
msgstr "Gjennomsnittlig pris"
|
||||
@@ -1831,19 +1839,24 @@ msgstr "Endre strekkode"
|
||||
|
||||
msgid "Not enough in stock (not included in costs), %s ingredient missing"
|
||||
msgstr ""
|
||||
"Ikke nok igjen i beholdningen (ikke inkludert kost), %s ingrediens mangler"
|
||||
|
||||
msgid ""
|
||||
"Based on the prices of the default consume rule which is \"Opened first, "
|
||||
"then first due first, then first in first out\""
|
||||
msgstr ""
|
||||
"Basert på prisene til standardregel \"Åpnet først, kommende utgangsdato "
|
||||
"først, først inn først ut\""
|
||||
|
||||
msgid ""
|
||||
"Not enough in stock (not included in costs), %1$s missing, %2$s already on "
|
||||
"shopping list"
|
||||
msgstr ""
|
||||
"Ikke nok igjen i beholdningen (ikke inkludert kost), %1$s mangler, %2$s "
|
||||
"allerede på handlelisten"
|
||||
|
||||
msgid "Quantity unit stock cannot be changed after first purchase"
|
||||
msgstr ""
|
||||
msgstr "Forpakning i beholdning kan ikke endres etter første kjøp"
|
||||
|
||||
msgid "Clear filter"
|
||||
msgstr "Tøm filter"
|
||||
@@ -1852,7 +1865,7 @@ msgid "Permissions for user %s"
|
||||
msgstr "Tillatelser for bruker %s"
|
||||
|
||||
msgid "Are you sure you want to remove full permissions for yourself?"
|
||||
msgstr ""
|
||||
msgstr "Er du sikker på at du ønsker å fjerne alle rettigheter for deg selv?"
|
||||
|
||||
msgid "Permissions saved"
|
||||
msgstr "Tillatelser lagret"
|
||||
@@ -1861,413 +1874,632 @@ msgid "You are not allowed to view this page"
|
||||
msgstr "Du har ikke tillatelse til å vise denne siden"
|
||||
|
||||
msgid "Page not found"
|
||||
msgstr ""
|
||||
msgstr "Page not found"
|
||||
|
||||
msgid "Unauthorized"
|
||||
msgstr ""
|
||||
msgstr "Unauthorized"
|
||||
|
||||
msgid "Error source"
|
||||
msgstr ""
|
||||
msgstr "Error source"
|
||||
|
||||
msgid "Error message"
|
||||
msgstr ""
|
||||
msgstr "Error message"
|
||||
|
||||
msgid "Stack trace"
|
||||
msgstr ""
|
||||
msgstr "Stack trace"
|
||||
|
||||
msgid "Easy error info copy & paste (for reporting)"
|
||||
msgstr ""
|
||||
msgstr "Easy error info copy & paste (for reporting)"
|
||||
|
||||
msgid "This page does not exist"
|
||||
msgstr ""
|
||||
msgstr "This page does not exist"
|
||||
|
||||
msgid "You will be redirected to the default page in %s seconds"
|
||||
msgstr ""
|
||||
msgstr "You will be redirected to the default page in %s seconds"
|
||||
|
||||
msgid "Server error"
|
||||
msgstr ""
|
||||
msgstr "Server error"
|
||||
|
||||
msgid "A server error occured while processing your request"
|
||||
msgstr ""
|
||||
msgstr "A server error occured while processing your request"
|
||||
|
||||
msgid "If you think this is a bug, please report it"
|
||||
msgstr ""
|
||||
msgstr "If you think this is a bug, please report it"
|
||||
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
msgstr "Språk"
|
||||
|
||||
msgid "User settings"
|
||||
msgstr ""
|
||||
msgstr "Brukerinnstillinger"
|
||||
|
||||
msgid "Default"
|
||||
msgstr ""
|
||||
msgstr "Standard"
|
||||
|
||||
msgid "Stock journal summary"
|
||||
msgstr ""
|
||||
msgstr "Beholdningslogg sammendrag"
|
||||
|
||||
msgid "Journal summary"
|
||||
msgstr ""
|
||||
msgstr "Logg sammendrag"
|
||||
|
||||
msgid "Journal summary for this product"
|
||||
msgstr ""
|
||||
msgstr "Logg sammendrag for dette produktet"
|
||||
|
||||
msgid "Consume exact amount"
|
||||
msgstr ""
|
||||
msgstr "Konsumer definert mengde"
|
||||
|
||||
msgid "Value"
|
||||
msgstr ""
|
||||
msgstr "Verdi"
|
||||
|
||||
msgid "%s total value"
|
||||
msgstr ""
|
||||
msgstr "%s total beholdningsverdi"
|
||||
|
||||
msgid ""
|
||||
"Show purchased date on purchase and inventory page (otherwise the purchased "
|
||||
"date defaults to today)"
|
||||
msgstr ""
|
||||
"Vis innkjøpsdato på innkjøp og beholdningssidene (ellers vil innkjøpsdato "
|
||||
"settes til i dag)"
|
||||
|
||||
msgid "Common"
|
||||
msgstr ""
|
||||
msgstr "Felles"
|
||||
|
||||
msgid "Decimal places allowed for amounts"
|
||||
msgstr ""
|
||||
msgstr "Desimaler kan brukes på antall"
|
||||
|
||||
msgid "Decimal places allowed for prices"
|
||||
msgstr ""
|
||||
msgstr "Desimaler kan brukes på priser"
|
||||
|
||||
msgid "Stock entries for this product"
|
||||
msgstr ""
|
||||
msgstr "Beholdningsoppføringer for dette produktet"
|
||||
|
||||
msgid "Edit shopping list"
|
||||
msgstr ""
|
||||
msgstr "Endre handleliste"
|
||||
|
||||
msgid "Save & continue to add quantity unit conversions & barcodes"
|
||||
msgstr ""
|
||||
"Lagre og fortsett for å legg til forpaknings konvertering og strekkoder"
|
||||
|
||||
msgid "Save & return to products"
|
||||
msgstr ""
|
||||
msgstr "Lagre og gå tilbake til produkter"
|
||||
|
||||
msgid "Save & continue to add conversions"
|
||||
msgstr ""
|
||||
msgstr "Lagre og fortsett å legge til konverteringer"
|
||||
|
||||
msgid "Save & return to quantity units"
|
||||
msgstr ""
|
||||
msgstr "Lagre og gå tilbake til forpakningstyper"
|
||||
|
||||
msgid "price"
|
||||
msgstr ""
|
||||
msgstr "pris"
|
||||
|
||||
msgid "New stock amount"
|
||||
msgstr ""
|
||||
msgstr "Ny beholdingsmengde"
|
||||
|
||||
msgid "Price per stock unit"
|
||||
msgstr ""
|
||||
msgstr "Pris per beholdningstype"
|
||||
|
||||
msgid "Table options"
|
||||
msgstr ""
|
||||
msgstr "Tabellalternativer"
|
||||
|
||||
msgid "This product is currently on a shopping list"
|
||||
msgstr ""
|
||||
msgstr "Dette produktet er allerede på en handleliste"
|
||||
|
||||
msgid "Undo transaction"
|
||||
msgstr ""
|
||||
msgstr "Angre transaksjonen"
|
||||
|
||||
msgid "Transaction type"
|
||||
msgstr ""
|
||||
msgstr "Transaksjonstype"
|
||||
|
||||
msgid "Transaction time"
|
||||
msgstr ""
|
||||
msgstr "Transaksjonstid"
|
||||
|
||||
msgid "Chore journal"
|
||||
msgstr ""
|
||||
msgstr "Statistikk husarbeid"
|
||||
|
||||
msgid "Track chore execution"
|
||||
msgstr ""
|
||||
msgstr "Registrerte husarbeidsoppgave"
|
||||
|
||||
msgid "Mark task as completed"
|
||||
msgstr ""
|
||||
msgstr "Merk oppgave som ferdig"
|
||||
|
||||
msgid "Track charge cycle"
|
||||
msgstr ""
|
||||
msgstr "Registrer lasesyklus"
|
||||
|
||||
msgid "Battery journal"
|
||||
msgstr ""
|
||||
msgstr "Batterilogg"
|
||||
|
||||
msgid "This product has a picture"
|
||||
msgstr ""
|
||||
msgstr "Dette produktet har et bilde"
|
||||
|
||||
msgid "Consume this stock entry as spoiled"
|
||||
msgstr ""
|
||||
msgstr "Konsumer denne som dårlig / råtten"
|
||||
|
||||
msgid "Configure user permissions"
|
||||
msgstr ""
|
||||
msgstr "Konfigurer brukerrettigheter"
|
||||
|
||||
msgid "Show a QR-Code for this API key"
|
||||
msgstr ""
|
||||
msgstr "Vis en QR-Kode for denne API nøkkelen"
|
||||
|
||||
msgid ""
|
||||
"This is the default quantity unit used when adding this product to the "
|
||||
"shopping list"
|
||||
msgstr ""
|
||||
"Dette er standard forpakningstørrelse som brukes når du legger dette "
|
||||
"produktet til handlelisten"
|
||||
|
||||
msgid ""
|
||||
"Show a warning when the due date of the purchased product is earlier than "
|
||||
"the next due date in stock"
|
||||
msgstr ""
|
||||
"Vis en advarsel når forfallsdatoen for det kjøpte produktet er tidligere enn"
|
||||
" neste forfallsdato i beholdningen"
|
||||
|
||||
msgid "This is due earlier than already in-stock items"
|
||||
msgstr ""
|
||||
msgstr "Denne forfaller tidligere enn produkter allerede i beholdningen"
|
||||
|
||||
msgid ""
|
||||
"When enabled, after changing/scanning a product and if all fields could be "
|
||||
"automatically populated (by product and/or barcode defaults), the "
|
||||
"transaction is automatically submitted"
|
||||
msgstr ""
|
||||
"Når aktivert, ved endring / skanning av et produkt, og hvis alle felt "
|
||||
"automatisk kan fylles ut (etter standardinnstillinger for produkt og / eller"
|
||||
" strekkode), sendes transaksjonen automatisk"
|
||||
|
||||
msgid "Quick consume amount"
|
||||
msgstr ""
|
||||
msgstr "Hurtigkonsumer"
|
||||
|
||||
msgid ""
|
||||
"This amount is used for the \"quick consume/open buttons\" on the stock "
|
||||
"overview page (related to quantity unit stock)"
|
||||
msgstr ""
|
||||
"Dette beløpet brukes til \"hurtigkonsumere / åpne-knappene\" på "
|
||||
"beholdningsoversikten (relatert til forpakninger lager)"
|
||||
|
||||
msgid "Copy"
|
||||
msgstr ""
|
||||
msgstr "Kopier"
|
||||
|
||||
msgid "Are you sure to remove this barcode?"
|
||||
msgstr ""
|
||||
msgstr "Er du sikker på at du vil fjerne denne strekkoden?"
|
||||
|
||||
msgid "Due date type"
|
||||
msgstr ""
|
||||
msgstr "Forfallsdatotype"
|
||||
|
||||
msgid ""
|
||||
"Based on the selected type, the highlighting on the stock overview page will"
|
||||
" be different"
|
||||
msgstr ""
|
||||
"Basert på valgt type vil uthevingen på beholdningsoversikten være annerledes"
|
||||
|
||||
msgid ""
|
||||
"Means that the product is maybe still safe to be consumed after its due date"
|
||||
" is reached"
|
||||
msgstr ""
|
||||
"Betyr at produktet fremdeles er trygt å konsumere etter at forfallsdato"
|
||||
|
||||
msgid "Expiration date"
|
||||
msgstr ""
|
||||
msgstr "Utløpsdato"
|
||||
|
||||
msgid ""
|
||||
"Means that the product is not safe to be consumed after its due date is "
|
||||
"reached"
|
||||
msgstr ""
|
||||
msgstr "Betyr at produktet ikke er trygt å konsumere etter at utløpsdato"
|
||||
|
||||
msgid ""
|
||||
"For purchases this amount of days will be added to today for the due date "
|
||||
"suggestion"
|
||||
msgstr ""
|
||||
"For kjøp blir dette antall dager lagt til i dag for forslaget på "
|
||||
"forfallsdato"
|
||||
|
||||
msgid "-1 means that this product will be never overdue"
|
||||
msgstr ""
|
||||
msgstr "-1 betyr at dette produktet aldri forfaller"
|
||||
|
||||
msgid "Default due days"
|
||||
msgstr ""
|
||||
msgstr "Standard forfallsdager"
|
||||
|
||||
msgid ""
|
||||
"When this product was marked as opened, the due date will be replaced by "
|
||||
"today + this amount of days (a value of 0 disables this)"
|
||||
"today + this amount of days, but only if the resulting date is not after the"
|
||||
" original due date (a value of 0 disables this)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Default due days after opened"
|
||||
msgstr ""
|
||||
msgstr "Standard forfallsdager etter åpning"
|
||||
|
||||
msgid ""
|
||||
"On moving this product to a freezer location (so when freezing it), the due "
|
||||
"date will be replaced by today + this amount of days"
|
||||
msgstr ""
|
||||
"Når du flytter dette produktet til en fryser (når du fryser det), vil "
|
||||
"forfallsdatoen erstattes av i dag + dette antall dager"
|
||||
|
||||
msgid "Default due days after freezing"
|
||||
msgstr ""
|
||||
msgstr "Standard forfallsdager etter frysing"
|
||||
|
||||
msgid ""
|
||||
"On moving this product from a freezer location (so when thawing it), the due"
|
||||
" date will be replaced by today + this amount of days"
|
||||
msgstr ""
|
||||
"Når du flytter dette produktet fra en fryser (når du tiner det), vil "
|
||||
"forfallsdatoen erstattes med i dag + dette antall dager"
|
||||
|
||||
msgid "Default due days after thawing"
|
||||
msgstr ""
|
||||
msgstr "Standard forfallsdager etter tining"
|
||||
|
||||
msgid "Next due date"
|
||||
msgstr ""
|
||||
msgstr "Neste forfallsdato"
|
||||
|
||||
msgid "%s product is due"
|
||||
msgid_plural "%s products are due"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "%s produkt forfaller"
|
||||
msgstr[1] "%s produkter forfaller"
|
||||
|
||||
msgid "Due date"
|
||||
msgstr ""
|
||||
msgstr "Forfallsdato"
|
||||
|
||||
msgid "Never overdue"
|
||||
msgstr ""
|
||||
msgstr "Forfaller aldri"
|
||||
|
||||
msgid "%s product is expired"
|
||||
msgid_plural "%s products are expired"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "%s produkt har forfalt"
|
||||
msgstr[1] "%s produkter er utløpt på dato"
|
||||
|
||||
msgid "Expired"
|
||||
msgstr ""
|
||||
msgstr "Utgått"
|
||||
|
||||
msgid "Due soon days"
|
||||
msgstr ""
|
||||
msgstr "Forfaller snart dager"
|
||||
|
||||
msgid "Add overdue/expired products"
|
||||
msgstr ""
|
||||
msgstr "Legg til forfalte produkter"
|
||||
|
||||
msgid ""
|
||||
"Products with tare weight enabled are currently not supported for transfer"
|
||||
msgstr ""
|
||||
"Produkter med taravekt aktivert støttes for øyeblikket ikke for overføring"
|
||||
|
||||
msgid ""
|
||||
"This cannot be lower than %1$s or equal %2$s and needs to be a valid number "
|
||||
"with max. %3$s decimal places"
|
||||
msgstr ""
|
||||
"Dette kan ikke være lavere enn %1$s eller likt %2$s og må være et gyldig "
|
||||
"tall med maks %3$s desimaler"
|
||||
|
||||
msgid ""
|
||||
"This must be between %1$s and %2$s, cannot equal %3$s and needs to be a "
|
||||
"valid number with max. %4$s decimal places"
|
||||
msgstr ""
|
||||
"Dette må være mellom%1$s og %2$s kan ikke være samme som %3$s og må være et "
|
||||
"gyldig tall med maks %4$s desimaler"
|
||||
|
||||
msgid ""
|
||||
"This cannot be lower than %1$s and needs to be a valid number with max. %2$s"
|
||||
" decimal places"
|
||||
msgstr ""
|
||||
"Dette kan ikke være lavere enn %1$s og må være et gyldig tall med maks %2$s "
|
||||
"desimaler"
|
||||
|
||||
msgid ""
|
||||
"This must between %1$s and %2$s and needs to be a valid number with max. "
|
||||
"%3$s decimal places"
|
||||
msgstr ""
|
||||
"Dette må være mellom %1$s og %2$s og må være et gyldig nummer med maks %3$s "
|
||||
"desimaler"
|
||||
|
||||
msgid ""
|
||||
"Automatically do the booking using the last price and the amount of the "
|
||||
"shopping list item, if the product has \"Default due days\" set"
|
||||
msgstr ""
|
||||
"Gjør gjennomføringen automatisk med den siste prisen og beløpet på "
|
||||
"handlelistpunktet, hvis produktet er satt til \"Standard forfallsdato\""
|
||||
|
||||
msgid ""
|
||||
"When moving products from/to a freezer location, the products due date is "
|
||||
"automatically adjusted according to the product settings"
|
||||
msgstr ""
|
||||
"Når du flytter produkter fra / til en fryser, justeres produktets "
|
||||
"forfallsdato automatisk i henhold til produktinnstillingene"
|
||||
|
||||
msgid "This is the internal field name, e. g. for the API"
|
||||
msgstr ""
|
||||
msgstr "Dette er det interne feltnavnet, f.eks. g. for API"
|
||||
|
||||
msgid "This is used to display the field on the frontend"
|
||||
msgstr ""
|
||||
msgstr "Dette brukes til å vise feltet på framsiden"
|
||||
|
||||
msgid "Multiple Userfields will be ordered by that number on the input form"
|
||||
msgstr ""
|
||||
msgstr "Flere brukerfelt vil bli sortert etter nummeret på inndata feltet"
|
||||
|
||||
msgid "Sort number"
|
||||
msgstr ""
|
||||
msgstr "Sorteringsnummer"
|
||||
|
||||
msgid "Download file"
|
||||
msgstr ""
|
||||
msgstr "Last ned fil"
|
||||
|
||||
msgid "Use the products \"Quick consume amount\""
|
||||
msgstr ""
|
||||
msgstr "Bruk produktets \"Hurtigkonsumer\""
|
||||
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
msgstr "Avslått"
|
||||
|
||||
msgid ""
|
||||
"This also removes any stock amount, the journal and all other references of "
|
||||
"this product - consider disabling it instead, if you want to keep that and "
|
||||
"just hide the product."
|
||||
msgstr ""
|
||||
"Dette fjerner beholdningsantall, logg og alle andre referanser til dette "
|
||||
"produktet - vurdere å deaktivere det i stedet, hvis du vil beholde det og "
|
||||
"bare skjule produktet."
|
||||
|
||||
msgid "Show disabled"
|
||||
msgstr ""
|
||||
msgstr "Vis avslåtte"
|
||||
|
||||
msgid "Never show on stock overview"
|
||||
msgstr ""
|
||||
msgstr "Vis aldri på beholdningsoversikt"
|
||||
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
msgstr "Ingen"
|
||||
|
||||
msgid "Group by"
|
||||
msgstr ""
|
||||
msgstr "Grupperes etter"
|
||||
|
||||
msgid "Ingredient group"
|
||||
msgstr ""
|
||||
msgstr "Ingrediensgruppe"
|
||||
|
||||
msgid "Reset"
|
||||
msgstr ""
|
||||
msgstr "Reset"
|
||||
|
||||
msgid "Are you sure to reset the table options?"
|
||||
msgstr ""
|
||||
msgstr "Er du sikker på at du ønsker resette tabelen?"
|
||||
|
||||
msgid "Hide/view columns"
|
||||
msgstr ""
|
||||
msgstr "Skjul / vis kolonner"
|
||||
|
||||
msgid ""
|
||||
"A different amount/unit can then be used below while for stock fulfillment "
|
||||
"checking it is sufficient when any amount of the product in stock"
|
||||
msgstr ""
|
||||
"En annen mengde / enhet kan deretter brukes nedenfor, mens det er "
|
||||
"tilstrekkelig når en hvilken som helst mengde av produktet er i beholdningen"
|
||||
|
||||
msgid "Last price (Unit)"
|
||||
msgstr ""
|
||||
msgstr "Siste pris (Enhet)"
|
||||
|
||||
msgid "Last price (Total)"
|
||||
msgstr ""
|
||||
msgstr "Siste pris (Total)"
|
||||
|
||||
msgid "Show header"
|
||||
msgstr ""
|
||||
msgstr "Vis overskrift"
|
||||
|
||||
msgid "Group by product group"
|
||||
msgstr ""
|
||||
msgstr "Gruppèr etter produktgruppe"
|
||||
|
||||
msgid "Table"
|
||||
msgstr ""
|
||||
msgstr "Tabel"
|
||||
|
||||
msgid "Layout type"
|
||||
msgstr ""
|
||||
msgstr "Layout type"
|
||||
|
||||
msgid "Merge this product with another one"
|
||||
msgstr ""
|
||||
msgstr "Slå sammen dette produktet med et annet"
|
||||
|
||||
msgid "Merge products"
|
||||
msgstr ""
|
||||
msgstr "Slå sammen produkter"
|
||||
|
||||
msgid "Product to keep"
|
||||
msgstr ""
|
||||
msgstr "Produkt som skal beholdes"
|
||||
|
||||
msgid "Product to remove"
|
||||
msgstr ""
|
||||
msgstr "Produkt som skal fjernes"
|
||||
|
||||
msgid "Error while merging products"
|
||||
msgstr ""
|
||||
msgstr "Feil under sammenslåing av produkter"
|
||||
|
||||
msgid "After merging, this product will be kept"
|
||||
msgstr ""
|
||||
msgstr "Etter sammenslåing så vil dette produktet bli beholdt"
|
||||
|
||||
msgid ""
|
||||
"After merging, all occurences of this product will be replaced by \"Product "
|
||||
"to keep\" (means this product will not exist anymore)"
|
||||
msgstr ""
|
||||
"Etter sammenslåing vil alle forekomster av dette produktet bli erstattet av "
|
||||
"\"Produkt å beholde\" (dette betyr at produktet ikke vil eksistere lenger)"
|
||||
|
||||
msgid "Merge"
|
||||
msgstr ""
|
||||
msgstr "Sammenslå"
|
||||
|
||||
msgid "Title"
|
||||
msgstr ""
|
||||
msgstr "Tittel"
|
||||
|
||||
msgid "Link"
|
||||
msgstr ""
|
||||
msgstr "Link"
|
||||
|
||||
msgid ""
|
||||
"The stock overview page lists all products which are currently in-stock or "
|
||||
"below their min. stock amount - enable this to hide this product there "
|
||||
"always"
|
||||
msgstr ""
|
||||
"Beholdningsoversikten viser alle produkter som er i beholdningen eller under"
|
||||
" min. beholdningsantall - aktiver dette for å alltid skjule dette produktet"
|
||||
|
||||
msgid "Print options"
|
||||
msgstr ""
|
||||
msgstr "Printevalg"
|
||||
|
||||
msgid "A product or a note is required"
|
||||
msgstr "Et produkt eller en merknad kreves"
|
||||
|
||||
msgid "grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid "Download"
|
||||
msgstr ""
|
||||
|
||||
# Example: Download *Product* grocycode
|
||||
msgid "Download %s grocycode"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"grocycode is a unique referer to this %s in your grocy instance - print it "
|
||||
"onto a label and scan it like any other barcode"
|
||||
msgstr ""
|
||||
|
||||
# Abbreviation for "due date"
|
||||
msgid "DD"
|
||||
msgstr ""
|
||||
|
||||
msgid "Print on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry label"
|
||||
msgstr ""
|
||||
|
||||
msgid "No label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Single label"
|
||||
msgstr ""
|
||||
|
||||
msgid "Label per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid "Allow label printing per unit"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Allow printing of one label per unit on purchase (after conversion) - e.g. 1"
|
||||
" purchased pack adding 10 pieces of stock would print 10 labels"
|
||||
msgstr ""
|
||||
|
||||
msgid "Error while executing WebHook"
|
||||
msgstr ""
|
||||
|
||||
# Example: Print *Product* grocycode on label printer
|
||||
msgid "Print %s grocycode on label printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Open stock entry label in new window"
|
||||
msgstr ""
|
||||
|
||||
msgid "Thermal printer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Printing"
|
||||
msgstr ""
|
||||
|
||||
msgid "Connecting to printer..."
|
||||
msgstr ""
|
||||
|
||||
msgid "Unable to print"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only done items"
|
||||
msgstr ""
|
||||
|
||||
msgid "Show only in-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Product description"
|
||||
msgstr ""
|
||||
|
||||
# Example: *3.21 USD* per *Pack*
|
||||
msgid "%1$s per %2$s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mark this item as undone"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory"
|
||||
msgstr ""
|
||||
|
||||
msgid "Mandatory Userfield"
|
||||
msgstr ""
|
||||
|
||||
msgid "When enabled, then this field must be filled on the destination form"
|
||||
msgstr ""
|
||||
|
||||
msgid "In-stock products"
|
||||
msgstr ""
|
||||
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
msgid "Should not be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, on moving this product to a freezer location (so when freezing"
|
||||
" it), a warning will be shown"
|
||||
msgstr ""
|
||||
|
||||
msgid "This product shouldn't be frozen"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy all meal plan entries of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "A date is required"
|
||||
msgstr ""
|
||||
|
||||
msgid "Day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy this day"
|
||||
msgstr ""
|
||||
|
||||
msgid "Date range"
|
||||
msgstr ""
|
||||
|
||||
msgid "%s month"
|
||||
msgid_plural "%s months"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%s year"
|
||||
msgid_plural "%s years"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "Display product"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy recipe"
|
||||
msgstr ""
|
||||
|
||||
msgid "Copy of %s"
|
||||
msgstr ""
|
||||
|
||||
msgid "Add decimal separator automatically for price inputs"
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"When enabled, you always have to enter the value including decimal places, "
|
||||
"the decimal separator will be automatically added based on the amount of "
|
||||
"allowed decimal places"
|
||||
msgstr ""
|
||||
|
||||
msgid "Stock entry"
|
||||
msgstr ""
|
||||
|
||||
msgid "Configure sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Meal plan sections"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Sections will be ordered by that number on the meal plan"
|
||||
msgstr ""
|
||||
|
||||
msgid "Edit meal plan section"
|
||||
msgstr ""
|
||||
|
||||
msgid "Are you sure to delete meal plan section \"%s\"?"
|
||||
msgstr ""
|
||||
|
||||
msgid "Section"
|
||||
msgstr ""
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#
|
||||
# Translators:
|
||||
# Marius Borø <blizzwave@gmail.com>, 2019
|
||||
# Marius Borø <blizzwave@gmail.com>, 2021
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-05-01T17:59:17+00:00\n"
|
||||
"PO-Revision-Date: 2019-05-01 17:43+0000\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2019\n"
|
||||
"Last-Translator: Marius Borø <blizzwave@gmail.com>, 2021\n"
|
||||
"Language-Team: Norwegian (https://www.transifex.com/grocy/teams/93189/no/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -59,12 +59,12 @@ msgstr "link"
|
||||
|
||||
# Link (with title)
|
||||
msgid "link-with-title"
|
||||
msgstr ""
|
||||
msgstr "link-with-title"
|
||||
|
||||
# File
|
||||
msgid "file"
|
||||
msgstr ""
|
||||
msgstr "file"
|
||||
|
||||
# Image
|
||||
msgid "image"
|
||||
msgstr ""
|
||||
msgstr "image"
|
||||
|
@@ -402,3 +402,12 @@ msgstr "Tamilski"
|
||||
|
||||
msgid "Finnish"
|
||||
msgstr "Fiński"
|
||||
|
||||
msgid "Breakfast"
|
||||
msgstr ""
|
||||
|
||||
msgid "Lunch"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dinner"
|
||||
msgstr ""
|
||||
|