diff --git a/config-dist.php b/config-dist.php
index 58ea7b6f..1eed9b62 100644
--- a/config-dist.php
+++ b/config-dist.php
@@ -1,4 +1,7 @@
view->set('version', $applicationService->GetInstalledVersion());
+
+ $localizationService = new LocalizationService(CULTURE);
+ $container->view->set('localizationStrings', $localizationService->GetCurrentCultureLocalizations());
+ $container->view->set('L', function($text, ...$placeholderValues) use($localizationService)
+ {
+ return $localizationService->Localize($text, ...$placeholderValues);
+ });
}
protected $AppContainer;
diff --git a/localization/de.php b/localization/de.php
new file mode 100644
index 00000000..e4da8043
--- /dev/null
+++ b/localization/de.php
@@ -0,0 +1,135 @@
+ 'Bestand',
+ '#1 products with #2 units in stock' => '#1 Produkte (#2 Einheiten) vorrätig',
+ '#1 products expiring within the next #2 days' => '#1 Produkte laufen innerhalb der nächsten #2 Tage ab',
+ '#1 products are already expired' => '#1 Produkte sind bereits abgelaufen',
+ '#1 products are below defined min. stock amount' => '#1 Produkte sind unter Mindestbestand',
+ 'Product' => 'Produkt',
+ 'Amount' => 'Menge',
+ 'Next best before date' => 'Nächstes MHD',
+ 'Logout' => 'Abmelden',
+ 'Habits overview' => 'Gewohnheiten',
+ 'Batteries overview' => 'Batterien',
+ 'Purchase' => 'Einkauf',
+ 'Consume' => 'Verbrauch',
+ 'Inventory' => 'Inventur',
+ 'Shopping list' => 'Einkaufszettel',
+ 'Habit tracking' => 'Gewohnheit-Ausführung',
+ 'Battery tracking' => 'Batterie-Ladzyklus',
+ 'Products' => 'Produkte',
+ 'Locations' => 'Standorte',
+ 'Quantity units' => 'Mengeneinheiten',
+ 'Habits' => 'Gewohnheiten',
+ 'Batteries' => 'Batterien',
+ 'Habit' => 'Gewohnheit',
+ 'Next estimated tracking' => 'Nächste geplante Ausführung',
+ 'Last tracked' => 'Zuletzt ausgeführt',
+ 'Battery' => 'Batterie',
+ 'Last charged' => 'Zuletzt geladen',
+ 'Next planned charge cycle' => 'Nächster geplanter Ladezyklus',
+ 'Best before' => 'MHD',
+ 'OK' => 'OK',
+ 'Product overview' => 'Produktübersicht',
+ 'Stock quantity unit' => 'Mengeneinheit Bestand',
+ 'Stock amount' => 'Bestand',
+ 'Last purchased' => 'Zuletzt gekauft',
+ 'Last used' => 'Zuletzt benutzt',
+ 'Spoiled' => 'Verdorben',
+ 'Barcode lookup is disabled' => 'Barcode-Suche ist deaktiviert',
+ 'will be added to the list of barcodes for the selected product on submit' => 'wird der Liste der Barcodes für das ausgewählte Produkt beim Speichern hinzugefügt',
+ 'New amount' => 'Neue Menge',
+ 'Note' => 'Notiz',
+ 'Tracked time' => 'Ausführungszeit',
+ 'Habit overview' => 'Gewohnheit Übersicht',
+ 'Tracked count' => 'Ausführungsanzahl',
+ 'Battery overview' => 'Batterie Übersicht',
+ 'Charge cycles count' => 'Ladezyklen',
+ 'Create shopping list item' => 'Einkaufszettel Eintrag erstellen',
+ 'Edit shopping list item' => 'Einkaufszettel Eintrag bearbeiten',
+ '#1 units were automatically added and will apply in addition to the amount entered here' => '#1 Einheiten wurden automatisch hinzugefügt und gelten zusätzlich der hier eingegebenen Menge',
+ 'Save' => 'Speichern',
+ 'Add' => 'Hinzufügen',
+ 'Name' => 'Name',
+ 'Location' => 'Standort',
+ 'Min. stock amount' => 'Mindestbestand',
+ 'QU purchase' => 'ME Einkauf',
+ 'QU stock' => 'ME Bestand',
+ 'QU factor' => 'ME-Faktor',
+ 'Description' => 'Beschreibung',
+ 'Create product' => 'Produkt erstellen',
+ 'Barcode(s)' => 'Barcode(s)',
+ 'Minimum stock amount' => 'Mindestbestand',
+ 'Default best before days' => 'Standard Haltbarkeit in Tagen',
+ 'Quantity unit purchase' => 'Mengeneinheit Einkauf',
+ 'Quantity unit stock' => 'Mengeneinheit Bestand',
+ 'Factor purchase to stock quantity unit' => 'Faktor Mengeneinheit Einkauf zu Mengeneinheit Bestand',
+ 'Create location' => 'Standort erstellen',
+ 'Create quantity unit' => 'Mengeneinheit erstellen',
+ 'Period type' => 'Periodentyp',
+ 'Period days' => 'Tage/Periode',
+ 'Create habit' => 'Gewohnheit erstellen',
+ 'Used in' => 'Benutzt in',
+ 'Create battery' => 'Batterie erstellen',
+ 'Edit battery' => 'Batterie bearbeiten',
+ 'Edit habit' => 'Gewohnheit bearbeiten',
+ 'Edit quantity unit' => 'Mengeneinheit bearbeiten',
+ 'Edit product' => 'Produkt bearbeiten',
+ 'Edit location' => 'Standort bearbeiten',
+ 'Record data' => 'Daten erfassen',
+ 'Manage master data' => 'Stammdaten verwalten',
+ 'This will apply to added products' => 'Dies gilt für hinzugefügte Produkte',
+ 'never' => 'nie',
+ 'Add products that are below defined min. stock amount' => 'Produkte unter Mindestbestand hinzufügen',
+ 'For purchases this amount of days will be added to today for the best before date suggestion' => 'Bei Einkäufen wird hierauf basierend das MHD vorausgefüllt',
+ 'This means 1 #1 purchased will be converted into #2 #3 in stock' => 'Das bedeutet 1 #1 im Einkauf entsprechen #2 #3 im Bestand',
+ 'Login' => 'Anmelden',
+ 'Username' => 'Benutzername',
+ 'Password' => 'Passwort',
+ 'Invalid credentials, please try again' => 'Ungültige Zugangsdaten, bitte versuche es erneut',
+
+ //Constants
+ 'manually' => 'Manuell',
+ 'dynamic-regular' => 'Dynamisch regelmäßig',
+
+ //Technical component translations
+ 'timeago_locale' => 'de',
+ 'timeago_nan' => 'vor NaN Jahren',
+ 'moment_locale' => 'de',
+ 'bootstrap_datepicker_locale' => 'de',
+ 'datatables_localization' => '{"sEmptyTable":"Keine Daten in der Tabelle vorhanden","sInfo":"_START_ bis _END_ von _TOTAL_ Einträgen","sInfoEmpty":"Keine Daten vorhanden","sInfoFiltered":"(gefiltert von _MAX_ Einträgen)","sInfoPostFix":"","sInfoThousands":".","sLengthMenu":"_MENU_ Einträge anzeigen","sLoadingRecords":"Wird geladen ..","sProcessing":"Bitte warten ..","sSearch":"Suchen","sZeroRecords":"Keine Einträge vorhanden","oPaginate":{"sFirst":"Erste","sPrevious":"Zurück","sNext":"Nächste","sLast":"Letzte"},"oAria":{"sSortAscending":": aktivieren, um Spalte aufsteigend zu sortieren","sSortDescending":": aktivieren, um Spalte absteigend zu sortieren"},"select":{"rows":{"0":"Zum Auswählen auf eine Zeile klicken","1":"1 Zeile ausgewählt","_":"%d Zeilen ausgewählt"}},"buttons":{"print":"Drucken","colvis":"Spalten","copy":"Kopieren","copyTitle":"In Zwischenablage kopieren","copyKeys":"Taste ctrl oder ⌘ + C um Tabelle
in Zwischenspeicher zu kopieren.
Um abzubrechen die Nachricht anklicken oder Escape drücken.","copySuccess":{"1":"1 Spalte kopiert","_":"%d Spalten kopiert"}}}',
+
+ //Demo data
+ 'Cookies' => 'Cookies',
+ 'Chocolate' => 'Schokolade',
+ 'Pantry' => 'Vorratskammer',
+ 'Candy cupboard' => 'Süßigkeitenschrank',
+ 'Tinned food cupboard' => 'Konservenschrank',
+ 'Fridge' => 'Kühlschrank',
+ 'Piece' => 'Stück',
+ 'Pack' => 'Packung',
+ 'Glass' => 'Glas',
+ 'Tin' => 'Dose',
+ 'Can' => 'Becher',
+ 'Bunch' => 'Bund',
+ 'Gummy bears' => 'Gummibärchen',
+ 'Crisps' => 'Chips',
+ 'Eggs' => 'Eier',
+ 'Noodles' => 'Nudeln',
+ 'Pickles' => 'Essiggurken',
+ 'Gulash soup' => 'Gulaschsuppe',
+ 'Yogurt' => 'Joghurt',
+ 'Cheese' => 'Käse',
+ 'Cold cuts' => 'Aufschnitt',
+ 'Paprika' => 'Paprika',
+ 'Cucumber' => 'Gurke',
+ 'Radish' => 'Radieschen',
+ 'Tomato' => 'Tomaten',
+ 'Changed towels in the bathroom' => 'Handtücher im Bad gewechselt',
+ 'Cleaned the kitchen floor' => 'Küchenboden gewischt',
+ 'Warranty ends' => 'Garantie endet',
+ 'TV remote control' => 'TV Fernbedienung',
+ 'Alarm clock' => 'Wecker',
+ 'Heat remote control' => 'Fernbedienung Heizung'
+);
diff --git a/localization/en.php b/localization/en.php
new file mode 100644
index 00000000..36516dd8
--- /dev/null
+++ b/localization/en.php
@@ -0,0 +1,14 @@
+ 'Manually',
+ 'dynamic-regular' => 'Dynamic regular',
+
+ //Technical component translations
+ 'timeago_locale' => 'en',
+ 'timeago_nan' => 'NaN years ago',
+ 'moment_locale' => '',
+ 'bootstrap_datepicker_locale' => '',
+ 'datatables_localization' => '{"sEmptyTable":"No data available in table","sInfo":"Showing _START_ to _END_ of _TOTAL_ entries","sInfoEmpty":"Showing 0 to 0 of 0 entries","sInfoFiltered":"(filtered from _MAX_ total entries)","sInfoPostFix":"","sInfoThousands":",","sLengthMenu":"Show _MENU_ entries","sLoadingRecords":"Loading...","sProcessing":"Processing...","sSearch":"Search:","sZeroRecords":"No matching records found","oPaginate":{"sFirst":"First","sLast":"Last","sNext":"Next","sPrevious":"Previous"},"oAria":{"sSortAscending":": activate to sort column ascending","sSortDescending":": activate to sort column descending"}}'
+);
diff --git a/migrations/0021.sql b/migrations/0021.sql
new file mode 100644
index 00000000..ee52c94a
--- /dev/null
+++ b/migrations/0021.sql
@@ -0,0 +1,11 @@
+DELETE FROM locations
+WHERE name = 'DefaultLocation';
+
+DELETE FROM quantity_units
+WHERE name = 'DefaultQuantityUnit';
+
+DELETE FROM products
+WHERE name = 'DefaultProduct1';
+
+DELETE FROM products
+WHERE name = 'DefaultProduct2';
diff --git a/public/css/grocy.css b/public/css/grocy.css
index 590a6f6d..b2c2fc1a 100644
--- a/public/css/grocy.css
+++ b/public/css/grocy.css
@@ -46,12 +46,12 @@
}
.nav-sidebar > li > a:hover {
- box-shadow: inset 4px 0 0 #337ab7;
+ box-shadow: inset 5px 0 0 #337ab7;
transition: all 0.3s;
}
.nav-sidebar > li > a:focus {
- box-shadow: inset 4px 0 0 #ab2230;
+ box-shadow: inset 5px 0 0 #ab2230;
transition: all 0.3s;
}
@@ -59,7 +59,7 @@
.nav-sidebar > .active > a:hover,
.nav-sidebar > .active > a:focus {
background-color: #d6d6d6;
- box-shadow: inset 4px 0 0 #ab2230;
+ box-shadow: inset 5px 0 0 #ab2230;
transition: all 0.3s;
}
@@ -114,7 +114,9 @@ a.discrete-link:focus {
font-weight: bold;
letter-spacing: -5px;
font-size: 2.2em;
- color: inherit !important;
+ color: #0b024c !important;
+ margin-left: 0 !important;
+ padding-left: 5px !important;
}
diff --git a/public/img/grocy.png b/public/img/grocy.png
index 37cc0608..b1e6c121 100644
Binary files a/public/img/grocy.png and b/public/img/grocy.png differ
diff --git a/public/js/grocy.js b/public/js/grocy.js
index 54afd320..5869d700 100644
--- a/public/js/grocy.js
+++ b/public/js/grocy.js
@@ -1,17 +1,27 @@
-var Grocy = { };
-Grocy.Components = { };
-
-$(function()
+L = function(text, ...placeholderValues)
{
- if (!Grocy.ActiveNav.isEmpty())
+ var localizedText = Grocy.LocalizationStrings[text];
+ if (localizedText === undefined)
{
- var menuItem = $('.nav').find("[data-nav-for-page='" + Grocy.ActiveNav + "']");
- menuItem.addClass('active');
- }
+ localizedText = text;
+ }
+
+ for (var i = 0; i < placeholderValues.length; i++)
+ {
+ localizedText = localizedText.replace('#' + (i + 1), placeholderValues[i]);
+ }
+
+ return localizedText;
+}
- $.timeago.settings.allowFuture = true;
- $('time.timeago').timeago();
-});
+if (!Grocy.ActiveNav.isEmpty())
+{
+ var menuItem = $('.nav').find("[data-nav-for-page='" + Grocy.ActiveNav + "']");
+ menuItem.addClass('active');
+}
+
+$.timeago.settings.allowFuture = true;
+$('time.timeago').timeago();
Grocy.FetchJson = function(url, success, error)
{
diff --git a/public/viewjs/batteries.js b/public/viewjs/batteries.js
index 2350f98a..51f39bc9 100644
--- a/public/viewjs/batteries.js
+++ b/public/viewjs/batteries.js
@@ -31,13 +31,11 @@
});
});
-$(function()
-{
- $('#batteries-table').DataTable({
- 'pageLength': 50,
- 'order': [[1, 'asc']],
- 'columnDefs': [
- { 'orderable': false, 'targets': 0 }
- ]
- });
+$('#batteries-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[1, 'asc']],
+ 'columnDefs': [
+ { 'orderable': false, 'targets': 0 }
+ ],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/public/viewjs/batteriesoverview.js b/public/viewjs/batteriesoverview.js
index e1a32725..d1f63bad 100644
--- a/public/viewjs/batteriesoverview.js
+++ b/public/viewjs/batteriesoverview.js
@@ -1,7 +1,5 @@
-$(function()
-{
- $('#batteries-overview-table').DataTable({
- 'pageLength': 50,
- 'order': [[1, 'desc']]
- });
+$('#batteries-overview-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[1, 'desc']],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/public/viewjs/batteryform.js b/public/viewjs/batteryform.js
index 8b3b8d8f..8b90d287 100644
--- a/public/viewjs/batteryform.js
+++ b/public/viewjs/batteryform.js
@@ -30,9 +30,6 @@
}
});
-$(function()
-{
- $('#name').focus();
- $('#battery-form').validator();
- $('#battery-form').validator('validate');
-});
+$('#name').focus();
+$('#battery-form').validator();
+$('#battery-form').validator('validate');
diff --git a/public/viewjs/batterytracking.js b/public/viewjs/batterytracking.js
index b86a919c..6bbf2f6c 100644
--- a/public/viewjs/batterytracking.js
+++ b/public/viewjs/batterytracking.js
@@ -44,50 +44,47 @@ $('#battery_id').on('change', function(e)
}
});
-$(function()
+$('.datetimepicker').datetimepicker(
{
- $('.datetimepicker').datetimepicker(
- {
- format: 'YYYY-MM-DD HH:mm:ss',
- showTodayButton: true,
- calendarWeeks: true,
- maxDate: moment()
- });
+ format: 'YYYY-MM-DD HH:mm:ss',
+ showTodayButton: true,
+ calendarWeeks: true,
+ maxDate: moment()
+});
- $('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
- $('#tracked_time').trigger('change');
+$('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
+$('#tracked_time').trigger('change');
- $('#tracked_time').on('focus', function(e)
+$('#tracked_time').on('focus', function(e)
+{
+ if ($('#battery_id_text_input').val().length === 0)
{
- if ($('#battery_id_text_input').val().length === 0)
+ $('#battery_id_text_input').focus();
+ }
+});
+
+$('.combobox').combobox({
+ appendId: '_text_input'
+});
+
+$('#battery_id').val('');
+$('#battery_id_text_input').focus();
+$('#battery_id_text_input').val('');
+$('#battery_id_text_input').trigger('change');
+
+$('#batterytracking-form').validator();
+$('#batterytracking-form').validator('validate');
+
+$('#batterytracking-form input').keydown(function(event)
+{
+ if (event.keyCode === 13) //Enter
+ {
+ if ($('#batterytracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
- $('#battery_id_text_input').focus();
+ event.preventDefault();
+ return false;
}
- });
-
- $('.combobox').combobox({
- appendId: '_text_input'
- });
-
- $('#battery_id').val('');
- $('#battery_id_text_input').focus();
- $('#battery_id_text_input').val('');
- $('#battery_id_text_input').trigger('change');
-
- $('#batterytracking-form').validator();
- $('#batterytracking-form').validator('validate');
-
- $('#batterytracking-form input').keydown(function(event)
- {
- if (event.keyCode === 13) //Enter
- {
- if ($('#batterytracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
- {
- event.preventDefault();
- return false;
- }
- }
- });
+ }
});
$('#tracked_time').on('change', function(e)
diff --git a/public/viewjs/components/batterycard.js b/public/viewjs/components/batterycard.js
index 267cd9ba..9a44ed38 100644
--- a/public/viewjs/components/batterycard.js
+++ b/public/viewjs/components/batterycard.js
@@ -6,11 +6,12 @@ Grocy.Components.BatteryCard.Refresh = function(batteryId)
function(batteryDetails)
{
$('#batterycard-battery-name').text(batteryDetails.battery.name);
+ $('#batterycard-battery-used_in').text(batteryDetails.battery.used_in);
$('#batterycard-battery-last-charged').text((batteryDetails.last_charged || 'never'));
$('#batterycard-battery-last-charged-timeago').text($.timeago(batteryDetails.last_charged || ''));
$('#batterycard-battery-charge-cycles-count').text((batteryDetails.charge_cycles_count || '0'));
- EmptyElementWhenMatches('#batterycard-battery-last-charged-timeago', 'NaN years ago');
+ EmptyElementWhenMatches('#batterycard-battery-last-charged-timeago', L('timeago_nan'));
},
function(xhr)
{
diff --git a/public/viewjs/components/datepicker.js b/public/viewjs/components/datepicker.js
index 0b62cf66..24fafe2f 100644
--- a/public/viewjs/components/datepicker.js
+++ b/public/viewjs/components/datepicker.js
@@ -9,11 +9,12 @@ $(function()
calendarWeeks: true,
orientation: 'bottom auto',
weekStart: 1,
- showOnFocus: false
+ showOnFocus: false,
+ language: L('bootstrap_datepicker_locale')
});
$('.datepicker').trigger('change');
- EmptyElementWhenMatches('#datepicker-timeago', 'NaN years ago');
+ EmptyElementWhenMatches('#datepicker-timeago', L('timeago_nan'));
});
$('.datepicker').on('keydown', function(e)
@@ -82,7 +83,7 @@ $('.datepicker').on('change', function(e)
}
$('#datepicker-timeago').text($.timeago($('.datepicker').val()));
- EmptyElementWhenMatches('#datepicker-timeago', 'NaN years ago');
+ EmptyElementWhenMatches('#datepicker-timeago', L('timeago_nan'));
});
$('#datepicker-button').on('click', function(e)
diff --git a/public/viewjs/components/datetimepicker.js b/public/viewjs/components/datetimepicker.js
index 303dc964..5a6ab3b0 100644
--- a/public/viewjs/components/datetimepicker.js
+++ b/public/viewjs/components/datetimepicker.js
@@ -5,6 +5,7 @@ $(function()
format: 'YYYY-MM-DD HH:mm:ss',
showTodayButton: true,
calendarWeeks: true,
- maxDate: moment()
+ maxDate: moment(),
+ locale: moment.locale('de')
});
});
diff --git a/public/viewjs/components/habitcard.js b/public/viewjs/components/habitcard.js
index 350c5c2f..9a4fac6b 100644
--- a/public/viewjs/components/habitcard.js
+++ b/public/viewjs/components/habitcard.js
@@ -10,7 +10,7 @@ Grocy.Components.HabitCard.Refresh = function (habitId)
$('#habitcard-habit-last-tracked-timeago').text($.timeago(habitDetails.last_tracked || ''));
$('#habitcard-habit-tracked-count').text((habitDetails.tracked_count || '0'));
- EmptyElementWhenMatches('#habitcard-habit-last-tracked-timeago', 'NaN years ago');
+ EmptyElementWhenMatches('#habitcard-habit-last-tracked-timeago', L('timeago_nan'));
},
function(xhr)
{
diff --git a/public/viewjs/components/productcard.js b/public/viewjs/components/productcard.js
index b49be651..bfa54fb9 100644
--- a/public/viewjs/components/productcard.js
+++ b/public/viewjs/components/productcard.js
@@ -9,13 +9,13 @@ Grocy.Components.ProductCard.Refresh = function(productId)
$('#productcard-product-stock-amount').text(productDetails.stock_amount || '0');
$('#productcard-product-stock-qu-name').text(productDetails.quantity_unit_stock.name);
$('#productcard-product-stock-qu-name2').text(productDetails.quantity_unit_stock.name);
- $('#productcard-product-last-purchased').text((productDetails.last_purchased || 'never').substring(0, 10));
+ $('#productcard-product-last-purchased').text((productDetails.last_purchased || L('never')).substring(0, 10));
$('#productcard-product-last-purchased-timeago').text($.timeago(productDetails.last_purchased || ''));
- $('#productcard-product-last-used').text((productDetails.last_used || 'never').substring(0, 10));
+ $('#productcard-product-last-used').text((productDetails.last_used || L('never')).substring(0, 10));
$('#productcard-product-last-used-timeago').text($.timeago(productDetails.last_used || ''));
- EmptyElementWhenMatches('#productcard-product-last-purchased-timeago', 'NaN years ago');
- EmptyElementWhenMatches('#productcard-product-last-used-timeago', 'NaN years ago');
+ EmptyElementWhenMatches('#productcard-product-last-purchased-timeago', L('timeago_nan'));
+ EmptyElementWhenMatches('#productcard-product-last-used-timeago', L('timeago_nan'));
},
function(xhr)
{
diff --git a/public/viewjs/consume.js b/public/viewjs/consume.js
index ae000b99..9f444c14 100644
--- a/public/viewjs/consume.js
+++ b/public/viewjs/consume.js
@@ -81,55 +81,52 @@ $('#product_id').on('change', function(e)
}
});
-$(function()
-{
- $('.combobox').combobox({
- appendId: '_text_input'
- });
-
- $('#product_id_text_input').on('change', function(e)
- {
- var input = $('#product_id_text_input').val().toString();
- var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
-
- if (possibleOptionElement.length > 0)
- {
- $('#product_id').val(possibleOptionElement.val());
- $('#product_id').data('combobox').refresh();
- $('#product_id').trigger('change');
- }
- });
-
- $('#amount').val(1);
- $('#product_id').val('');
- $('#product_id_text_input').focus();
- $('#product_id_text_input').val('');
- $('#product_id_text_input').trigger('change');
-
- $('#consume-form').validator();
- $('#consume-form').validator('validate');
-
- $('#amount').on('focus', function(e)
- {
- if ($('#product_id_text_input').val().length === 0)
- {
- $('#product_id_text_input').focus();
- }
- else
- {
- $(this).select();
- }
- });
-
- $('#consume-form input').keydown(function(event)
- {
- if (event.keyCode === 13) //Enter
- {
- if ($('#consume-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
- {
- event.preventDefault();
- return false;
- }
- }
- });
+$('.combobox').combobox({
+ appendId: '_text_input'
+});
+
+$('#product_id_text_input').on('change', function(e)
+{
+ var input = $('#product_id_text_input').val().toString();
+ var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
+
+ if (possibleOptionElement.length > 0)
+ {
+ $('#product_id').val(possibleOptionElement.val());
+ $('#product_id').data('combobox').refresh();
+ $('#product_id').trigger('change');
+ }
+});
+
+$('#amount').val(1);
+$('#product_id').val('');
+$('#product_id_text_input').focus();
+$('#product_id_text_input').val('');
+$('#product_id_text_input').trigger('change');
+
+$('#consume-form').validator();
+$('#consume-form').validator('validate');
+
+$('#amount').on('focus', function(e)
+{
+ if ($('#product_id_text_input').val().length === 0)
+ {
+ $('#product_id_text_input').focus();
+ }
+ else
+ {
+ $(this).select();
+ }
+});
+
+$('#consume-form input').keydown(function(event)
+{
+ if (event.keyCode === 13) //Enter
+ {
+ if ($('#consume-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
+ {
+ event.preventDefault();
+ return false;
+ }
+ }
});
diff --git a/public/viewjs/habitform.js b/public/viewjs/habitform.js
index 5970606e..b03384ea 100644
--- a/public/viewjs/habitform.js
+++ b/public/viewjs/habitform.js
@@ -30,12 +30,9 @@
}
});
-$(function()
-{
- $('#name').focus();
- $('#habit-form').validator();
- $('#habit-form').validator('validate');
-});
+$('#name').focus();
+$('#habit-form').validator();
+$('#habit-form').validator('validate');
$('.input-group-habit-period-type').on('change', function(e)
{
diff --git a/public/viewjs/habits.js b/public/viewjs/habits.js
index 42840c07..a34d0ce4 100644
--- a/public/viewjs/habits.js
+++ b/public/viewjs/habits.js
@@ -31,13 +31,11 @@
});
});
-$(function()
-{
- $('#habits-table').DataTable({
- 'pageLength': 50,
- 'order': [[1, 'asc']],
- 'columnDefs': [
- { 'orderable': false, 'targets': 0 }
- ]
- });
+$('#habits-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[1, 'asc']],
+ 'columnDefs': [
+ { 'orderable': false, 'targets': 0 }
+ ],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/public/viewjs/habitsoverview.js b/public/viewjs/habitsoverview.js
index 4d7fb551..1f2bb50c 100644
--- a/public/viewjs/habitsoverview.js
+++ b/public/viewjs/habitsoverview.js
@@ -1,7 +1,5 @@
-$(function()
-{
- $('#habits-overview-table').DataTable({
- 'pageLength': 50,
- 'order': [[1, 'desc']]
- });
+$('#habits-overview-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[1, 'desc']],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/public/viewjs/habittracking.js b/public/viewjs/habittracking.js
index 696314eb..7971e21f 100644
--- a/public/viewjs/habittracking.js
+++ b/public/viewjs/habittracking.js
@@ -44,42 +44,39 @@ $('#habit_id').on('change', function(e)
}
});
-$(function()
+$('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
+$('#tracked_time').trigger('change');
+
+$('#tracked_time').on('focus', function(e)
{
- $('#tracked_time').val(moment().format('YYYY-MM-DD HH:mm:ss'));
- $('#tracked_time').trigger('change');
-
- $('#tracked_time').on('focus', function(e)
+ if ($('#habit_id_text_input').val().length === 0)
{
- if ($('#habit_id_text_input').val().length === 0)
- {
- $('#habit_id_text_input').focus();
- }
- });
+ $('#habit_id_text_input').focus();
+ }
+});
- $('.combobox').combobox({
- appendId: '_text_input'
- });
+$('.combobox').combobox({
+ appendId: '_text_input'
+});
- $('#habit_id').val('');
- $('#habit_id_text_input').focus();
- $('#habit_id_text_input').val('');
- $('#habit_id_text_input').trigger('change');
+$('#habit_id').val('');
+$('#habit_id_text_input').focus();
+$('#habit_id_text_input').val('');
+$('#habit_id_text_input').trigger('change');
- $('#habittracking-form').validator();
- $('#habittracking-form').validator('validate');
+$('#habittracking-form').validator();
+$('#habittracking-form').validator('validate');
- $('#habittracking-form input').keydown(function(event)
+$('#habittracking-form input').keydown(function(event)
+{
+ if (event.keyCode === 13) //Enter
{
- if (event.keyCode === 13) //Enter
+ if ($('#habittracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
{
- if ($('#habittracking-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
- {
- event.preventDefault();
- return false;
- }
+ event.preventDefault();
+ return false;
}
- });
+ }
});
$('#tracked_time').on('keypress', function(e)
diff --git a/public/viewjs/inventory.js b/public/viewjs/inventory.js
index 5c9782b9..f3d7704b 100644
--- a/public/viewjs/inventory.js
+++ b/public/viewjs/inventory.js
@@ -87,169 +87,166 @@ $('#product_id').on('change', function(e)
}
});
-$(function()
-{
- $('.combobox').combobox({
- appendId: '_text_input'
- });
+$('.combobox').combobox({
+ appendId: '_text_input'
+});
- $('#product_id_text_input').on('change', function(e)
+$('#product_id_text_input').on('change', function(e)
+{
+ var input = $('#product_id_text_input').val().toString();
+ var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
+
+ if (GetUriParam('addbarcodetoselection') === undefined && possibleOptionElement.length > 0)
{
- var input = $('#product_id_text_input').val().toString();
- var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
-
- if (GetUriParam('addbarcodetoselection') === undefined && possibleOptionElement.length > 0)
+ $('#product_id').val(possibleOptionElement.val());
+ $('#product_id').data('combobox').refresh();
+ $('#product_id').trigger('change');
+ }
+ else
+ {
+ var optionElement = $("#product_id option:contains('" + input + "')").first();
+ if (input.length > 0 && optionElement.length === 0 && GetUriParam('addbarcodetoselection') === undefined )
{
- $('#product_id').val(possibleOptionElement.val());
- $('#product_id').data('combobox').refresh();
- $('#product_id').trigger('change');
- }
- else
- {
- var optionElement = $("#product_id option:contains('" + input + "')").first();
- if (input.length > 0 && optionElement.length === 0 && GetUriParam('addbarcodetoselection') === undefined )
- {
- bootbox.dialog({
- message: '' + input + ' could not be resolved to a product, how do you want to proceed?',
- title: 'Create or assign product',
- onEscape: function() { },
- size: 'large',
- backdrop: true,
- buttons: {
- cancel: {
- label: 'Cancel',
- className: 'btn-default',
- callback: function() { }
- },
- addnewproduct: {
- label: 'Add as new product',
- className: 'btn-success add-new-product-dialog-button',
- callback: function()
- {
- window.location.href = '/product/new?prefillname=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
- }
- },
- addbarcode: {
- label: 'Add as barcode to existing product',
- className: 'btn-info add-new-barcode-dialog-button',
- callback: function()
- {
- window.location.href = '/inventory?addbarcodetoselection=' + encodeURIComponent(input);
- }
- },
- addnewproductwithbarcode: {
- label: 'Add as new product + prefill barcode',
- className: 'btn-warning add-new-product-with-barcode-dialog-button',
- callback: function()
- {
- window.location.href = '/product/new?prefillbarcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
- }
+ bootbox.dialog({
+ message: '' + input + ' could not be resolved to a product, how do you want to proceed?',
+ title: 'Create or assign product',
+ onEscape: function() { },
+ size: 'large',
+ backdrop: true,
+ buttons: {
+ cancel: {
+ label: 'Cancel',
+ className: 'btn-default',
+ callback: function() { }
+ },
+ addnewproduct: {
+ label: 'Add as new product',
+ className: 'btn-success add-new-product-dialog-button',
+ callback: function()
+ {
+ window.location.href = '/product/new?prefillname=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
+ }
+ },
+ addbarcode: {
+ label: 'Add as barcode to existing product',
+ className: 'btn-info add-new-barcode-dialog-button',
+ callback: function()
+ {
+ window.location.href = '/inventory?addbarcodetoselection=' + encodeURIComponent(input);
+ }
+ },
+ addnewproductwithbarcode: {
+ label: 'Add as new product + prefill barcode',
+ className: 'btn-warning add-new-product-with-barcode-dialog-button',
+ callback: function()
+ {
+ window.location.href = '/product/new?prefillbarcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
}
- }).on('keypress', function(e)
- {
- if (e.key === 'B' || e.key === 'b')
- {
- $('.add-new-barcode-dialog-button').click();
- }
- if (e.key === 'p' || e.key === 'P')
- {
- $('.add-new-product-dialog-button').click();
- }
- if (e.key === 'a' || e.key === 'A')
- {
- $('.add-new-product-with-barcode-dialog-button').click();
- }
- });
- }
- }
- });
-
- $('#new_amount').val('');
- $('#best_before_date').val('');
- $('#product_id').val('');
- $('#product_id_text_input').focus();
- $('#product_id_text_input').val('');
- $('#product_id_text_input').trigger('change');
-
- $('#inventory-form').validator({
- custom: {
- 'isodate': function($el)
- {
- if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
- {
- return 'Wrong date format, needs to be YYYY-MM-DD';
}
- else if (moment($el.val()).isValid())
- {
- if (moment($el.val()).isBefore(moment(), 'day'))
- {
- return 'This value cannot be before today.';
- }
- }
- },
- 'notequal': function($el)
+ }).on('keypress', function(e)
{
- if ($el.val().length !== 0 && $el.val().toString() === $el.attr('not-equal').toString())
+ if (e.key === 'B' || e.key === 'b')
{
- return 'This value cannot be equal to ' + $el.attr('not-equal').toString();
+ $('.add-new-barcode-dialog-button').click();
}
- }
+ if (e.key === 'p' || e.key === 'P')
+ {
+ $('.add-new-product-dialog-button').click();
+ }
+ if (e.key === 'a' || e.key === 'A')
+ {
+ $('.add-new-product-with-barcode-dialog-button').click();
+ }
+ });
}
- });
- $('#inventory-form').validator('validate');
-
- $('#new_amount').on('focus', function(e)
- {
- if ($('#product_id_text_input').val().length === 0)
- {
- $('#product_id_text_input').focus();
- }
- else
- {
- $(this).select();
- }
- });
-
- $('#inventory-form input').keydown(function(event)
- {
- if (event.keyCode === 13) //Enter
- {
- if ($('#inventory-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
- {
- event.preventDefault();
- return false;
- }
- }
- });
-
- var prefillProduct = GetUriParam('createdproduct');
- if (prefillProduct !== undefined)
- {
- var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + prefillProduct + "']").first();
- if (possibleOptionElement.length === 0)
- {
- possibleOptionElement = $("#product_id option:contains('" + prefillProduct + "')").first();
- }
-
- if (possibleOptionElement.length > 0)
- {
- $('#product_id').val(possibleOptionElement.val());
- $('#product_id').data('combobox').refresh();
- $('#product_id').trigger('change');
- $('#new_amount').focus();
- }
- }
-
- var addBarcode = GetUriParam('addbarcodetoselection');
- if (addBarcode !== undefined)
- {
- $('#addbarcodetoselection').text(addBarcode);
- $('#flow-info-addbarcodetoselection').removeClass('hide');
- $('#barcode-lookup-disabled-hint').removeClass('hide');
}
});
+$('#new_amount').val('');
+$('#best_before_date').val('');
+$('#product_id').val('');
+$('#product_id_text_input').focus();
+$('#product_id_text_input').val('');
+$('#product_id_text_input').trigger('change');
+
+$('#inventory-form').validator({
+ custom: {
+ 'isodate': function($el)
+ {
+ if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
+ {
+ return 'Wrong date format, needs to be YYYY-MM-DD';
+ }
+ else if (moment($el.val()).isValid())
+ {
+ if (moment($el.val()).isBefore(moment(), 'day'))
+ {
+ return 'This value cannot be before today.';
+ }
+ }
+ },
+ 'notequal': function($el)
+ {
+ if ($el.val().length !== 0 && $el.val().toString() === $el.attr('not-equal').toString())
+ {
+ return 'This value cannot be equal to ' + $el.attr('not-equal').toString();
+ }
+ }
+ }
+});
+$('#inventory-form').validator('validate');
+
+$('#new_amount').on('focus', function(e)
+{
+ if ($('#product_id_text_input').val().length === 0)
+ {
+ $('#product_id_text_input').focus();
+ }
+ else
+ {
+ $(this).select();
+ }
+});
+
+$('#inventory-form input').keydown(function(event)
+{
+ if (event.keyCode === 13) //Enter
+ {
+ if ($('#inventory-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
+ {
+ event.preventDefault();
+ return false;
+ }
+ }
+});
+
+var prefillProduct = GetUriParam('createdproduct');
+if (prefillProduct !== undefined)
+{
+ var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + prefillProduct + "']").first();
+ if (possibleOptionElement.length === 0)
+ {
+ possibleOptionElement = $("#product_id option:contains('" + prefillProduct + "')").first();
+ }
+
+ if (possibleOptionElement.length > 0)
+ {
+ $('#product_id').val(possibleOptionElement.val());
+ $('#product_id').data('combobox').refresh();
+ $('#product_id').trigger('change');
+ $('#new_amount').focus();
+ }
+}
+
+var addBarcode = GetUriParam('addbarcodetoselection');
+if (addBarcode !== undefined)
+{
+ $('#addbarcodetoselection').text(addBarcode);
+ $('#flow-info-addbarcodetoselection').removeClass('hide');
+ $('#barcode-lookup-disabled-hint').removeClass('hide');
+}
+
$('#new_amount').on('keypress', function(e)
{
$('#new_amount').trigger('change');
diff --git a/public/viewjs/locationform.js b/public/viewjs/locationform.js
index 661ee560..f352620b 100644
--- a/public/viewjs/locationform.js
+++ b/public/viewjs/locationform.js
@@ -30,9 +30,6 @@
}
});
-$(function()
-{
- $('#name').focus();
- $('#location-form').validator();
- $('#location-form').validator('validate');
-});
+$('#name').focus();
+$('#location-form').validator();
+$('#location-form').validator('validate');
diff --git a/public/viewjs/locations.js b/public/viewjs/locations.js
index 7f6bcb17..9c64b1a1 100644
--- a/public/viewjs/locations.js
+++ b/public/viewjs/locations.js
@@ -31,13 +31,11 @@
});
});
-$(function()
-{
- $('#locations-table').DataTable({
- 'pageLength': 50,
- 'order': [[1, 'asc']],
- 'columnDefs': [
- { 'orderable': false, 'targets': 0 }
- ]
- });
+$('#locations-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[1, 'asc']],
+ 'columnDefs': [
+ { 'orderable': false, 'targets': 0 }
+ ],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/public/viewjs/login.js b/public/viewjs/login.js
index 6dd8e7c1..0ecea09e 100644
--- a/public/viewjs/login.js
+++ b/public/viewjs/login.js
@@ -1,12 +1,9 @@
-$(function()
+$('.logout-button').hide();
+
+$('#username').focus();
+
+if (GetUriParam('invalid') === 'true')
{
- $('.logout-button').hide();
-
- $('#username').focus();
-
- if (GetUriParam('invalid') === 'true')
- {
- $('#login-error').text('Invalid credentials, please try again.');
- $('#login-error').show();
- }
-});
+ $('#login-error').text(L('Invalid credentials, please try again'));
+ $('#login-error').show();
+}
diff --git a/public/viewjs/productform.js b/public/viewjs/productform.js
index a39a264a..7008db76 100644
--- a/public/viewjs/productform.js
+++ b/public/viewjs/productform.js
@@ -37,59 +37,51 @@
}
});
-$(function()
-{
- $('#barcode-taginput').tagsManager({
- 'hiddenTagListName': 'barcode',
- 'tagsContainer': '#barcode-taginput-container'
- });
-
- if (Grocy.EditMode === 'edit')
- {
- Grocy.FetchJson('/api/get-object/products/' + Grocy.EditObjectId,
- function (product)
- {
- if (product.barcode !== null && product.barcode.length > 0)
- {
- product.barcode.split(',').forEach(function(item)
- {
- $('#barcode-taginput').tagsManager('pushTag', item);
- });
- }
- },
- function(xhr)
- {
- console.error(xhr);
- }
- );
- }
-
- $('#qu_factor_purchase_to_stock').trigger('change');
- $('#name').focus();
- $('#product-form').validator();
- $('#product-form').validator('validate');
-
- var prefillName = GetUriParam('prefillname');
- if (prefillName !== undefined)
- {
- $('#name').val(prefillName);
- $('#name').focus();
- }
-
- var prefillBarcode = GetUriParam('prefillbarcode');
- if (prefillBarcode !== undefined)
- {
- $('#barcode-taginput').tagsManager('pushTag', prefillBarcode);
- $('#name').focus();
- }
+$('#barcode-taginput').tagsManager({
+ 'hiddenTagListName': 'barcode',
+ 'tagsContainer': '#barcode-taginput-container'
});
+if (Grocy.EditMode === 'edit')
+{
+ Grocy.FetchJson('/api/get-object/products/' + Grocy.EditObjectId,
+ function (product)
+ {
+ if (product.barcode !== null && product.barcode.length > 0)
+ {
+ product.barcode.split(',').forEach(function(item)
+ {
+ $('#barcode-taginput').tagsManager('pushTag', item);
+ });
+ }
+ },
+ function(xhr)
+ {
+ console.error(xhr);
+ }
+ );
+}
+
+var prefillName = GetUriParam('prefillname');
+if (prefillName !== undefined)
+{
+ $('#name').val(prefillName);
+ $('#name').focus();
+}
+
+var prefillBarcode = GetUriParam('prefillbarcode');
+if (prefillBarcode !== undefined)
+{
+ $('#barcode-taginput').tagsManager('pushTag', prefillBarcode);
+ $('#name').focus();
+}
+
$('.input-group-qu').on('change', function(e)
{
var factor = $('#qu_factor_purchase_to_stock').val();
if (factor > 1)
{
- $('#qu-conversion-info').text('This means 1 ' + $("#qu_id_purchase option:selected").text() + ' purchased will be converted into ' + (1 * factor).toString() + ' ' + $("#qu_id_stock option:selected").text() + ' in stock.');
+ $('#qu-conversion-info').text(L('This means 1 #1 purchased will be converted into #2 #3 in stock', $("#qu_id_purchase option:selected").text(), (1 * factor).toString(), $("#qu_id_stock option:selected").text()));
$('#qu-conversion-info').show();
}
else
@@ -97,3 +89,8 @@ $('.input-group-qu').on('change', function(e)
$('#qu-conversion-info').hide();
}
});
+
+$('#name').focus();
+$('#product-form').validator();
+$('#product-form').validator('validate');
+$('.input-group-qu').trigger('change');
diff --git a/public/viewjs/products.js b/public/viewjs/products.js
index 364cae4e..0cd05aa7 100644
--- a/public/viewjs/products.js
+++ b/public/viewjs/products.js
@@ -31,13 +31,11 @@
});
});
-$(function()
-{
- $('#products-table').DataTable({
- 'pageLength': 50,
- 'order': [[1, 'asc']],
- 'columnDefs': [
- { 'orderable': false, 'targets': 0 }
- ]
- });
+$('#products-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[1, 'asc']],
+ 'columnDefs': [
+ { 'orderable': false, 'targets': 0 }
+ ],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/public/viewjs/purchase.js b/public/viewjs/purchase.js
index cfd9c418..a7a98934 100644
--- a/public/viewjs/purchase.js
+++ b/public/viewjs/purchase.js
@@ -96,170 +96,167 @@ $('#product_id').on('change', function(e)
}
});
-$(function()
-{
- $('.combobox').combobox({
- appendId: '_text_input'
- });
+$('.combobox').combobox({
+ appendId: '_text_input'
+});
- $('#product_id_text_input').on('change', function(e)
+$('#product_id_text_input').on('change', function(e)
+{
+ var input = $('#product_id_text_input').val().toString();
+ var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
+
+ if (GetUriParam('addbarcodetoselection') === undefined && possibleOptionElement.length > 0)
{
- var input = $('#product_id_text_input').val().toString();
- var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
-
- if (GetUriParam('addbarcodetoselection') === undefined && possibleOptionElement.length > 0)
+ $('#product_id').val(possibleOptionElement.val());
+ $('#product_id').data('combobox').refresh();
+ $('#product_id').trigger('change');
+ }
+ else
+ {
+ var optionElement = $("#product_id option:contains('" + input + "')").first();
+ if (input.length > 0 && optionElement.length === 0 && GetUriParam('addbarcodetoselection') === undefined )
{
- $('#product_id').val(possibleOptionElement.val());
- $('#product_id').data('combobox').refresh();
- $('#product_id').trigger('change');
- }
- else
- {
- var optionElement = $("#product_id option:contains('" + input + "')").first();
- if (input.length > 0 && optionElement.length === 0 && GetUriParam('addbarcodetoselection') === undefined )
- {
- bootbox.dialog({
- message: '' + input + ' could not be resolved to a product, how do you want to proceed?',
- title: 'Create or assign product',
- onEscape: function() { },
- size: 'large',
- backdrop: true,
- buttons: {
- cancel: {
- label: 'Cancel',
- className: 'btn-default',
- callback: function() { }
- },
- addnewproduct: {
- label: 'Add as new product',
- className: 'btn-success add-new-product-dialog-button',
- callback: function()
- {
- window.location.href = '/product/new?prefillname=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
- }
- },
- addbarcode: {
- label: 'Add as barcode to existing product',
- className: 'btn-info add-new-barcode-dialog-button',
- callback: function()
- {
- window.location.href = '/purchase?addbarcodetoselection=' + encodeURIComponent(input);
- }
- },
- addnewproductwithbarcode: {
- label: 'Add as new product + prefill barcode',
- className: 'btn-warning add-new-product-with-barcode-dialog-button',
- callback: function()
- {
- window.location.href = '/product/new?prefillbarcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
- }
+ bootbox.dialog({
+ message: '' + input + ' could not be resolved to a product, how do you want to proceed?',
+ title: 'Create or assign product',
+ onEscape: function() { },
+ size: 'large',
+ backdrop: true,
+ buttons: {
+ cancel: {
+ label: 'Cancel',
+ className: 'btn-default',
+ callback: function() { }
+ },
+ addnewproduct: {
+ label: 'Add as new product',
+ className: 'btn-success add-new-product-dialog-button',
+ callback: function()
+ {
+ window.location.href = '/product/new?prefillname=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
+ }
+ },
+ addbarcode: {
+ label: 'Add as barcode to existing product',
+ className: 'btn-info add-new-barcode-dialog-button',
+ callback: function()
+ {
+ window.location.href = '/purchase?addbarcodetoselection=' + encodeURIComponent(input);
+ }
+ },
+ addnewproductwithbarcode: {
+ label: 'Add as new product + prefill barcode',
+ className: 'btn-warning add-new-product-with-barcode-dialog-button',
+ callback: function()
+ {
+ window.location.href = '/product/new?prefillbarcode=' + encodeURIComponent(input) + '&returnto=' + encodeURIComponent(window.location.pathname);
}
}
- }).on('keypress', function(e)
- {
- if (e.key === 'B' || e.key === 'b')
- {
- $('.add-new-barcode-dialog-button').click();
- }
- if (e.key === 'p' || e.key === 'P')
- {
- $('.add-new-product-dialog-button').click();
- }
- if (e.key === 'a' || e.key === 'A')
- {
- $('.add-new-product-with-barcode-dialog-button').click();
- }
- });
- }
- }
- });
-
- $('#amount').val(0);
- $('#best_before_date').val('');
- $('#product_id').val('');
- $('#product_id_text_input').focus();
- $('#product_id_text_input').val('');
- $('#product_id_text_input').trigger('change');
-
- $('#purchase-form').validator({
- custom: {
- 'isodate': function($el)
- {
- if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
- {
- return 'Wrong date format, needs to be YYYY-MM-DD';
}
- else if (moment($el.val()).isValid())
- {
- if (moment($el.val()).isBefore(moment(), 'day'))
- {
- return 'This value cannot be before today.';
- }
- }
- }
- }
- });
- $('#purchase-form').validator('validate');
-
- $('#best_before_date').on('focus', function(e)
- {
- if ($('#product_id_text_input').val().length === 0)
- {
- $('#product_id_text_input').focus();
- }
- });
-
- $('#amount').on('focus', function(e)
- {
- if ($('#product_id_text_input').val().length === 0)
- {
- $('#product_id_text_input').focus();
- }
- else
- {
- $(this).select();
- }
- });
-
- $('#purchase-form input').keydown(function(event)
- {
- if (event.keyCode === 13) //Enter
- {
- if ($('#purchase-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
+ }).on('keypress', function(e)
{
- event.preventDefault();
- return false;
- }
+ if (e.key === 'B' || e.key === 'b')
+ {
+ $('.add-new-barcode-dialog-button').click();
+ }
+ if (e.key === 'p' || e.key === 'P')
+ {
+ $('.add-new-product-dialog-button').click();
+ }
+ if (e.key === 'a' || e.key === 'A')
+ {
+ $('.add-new-product-with-barcode-dialog-button').click();
+ }
+ });
}
- });
-
- var prefillProduct = GetUriParam('createdproduct');
- if (prefillProduct !== undefined)
- {
- var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + prefillProduct + "']").first();
- if (possibleOptionElement.length === 0)
- {
- possibleOptionElement = $("#product_id option:contains('" + prefillProduct + "')").first();
- }
-
- if (possibleOptionElement.length > 0)
- {
- $('#product_id').val(possibleOptionElement.val());
- $('#product_id').data('combobox').refresh();
- $('#product_id').trigger('change');
- $('#best_before_date').focus();
- }
- }
-
- var addBarcode = GetUriParam('addbarcodetoselection');
- if (addBarcode !== undefined)
- {
- $('#addbarcodetoselection').text(addBarcode);
- $('#flow-info-addbarcodetoselection').removeClass('hide');
- $('#barcode-lookup-disabled-hint').removeClass('hide');
}
});
+$('#amount').val(0);
+$('#best_before_date').val('');
+$('#product_id').val('');
+$('#product_id_text_input').focus();
+$('#product_id_text_input').val('');
+$('#product_id_text_input').trigger('change');
+
+$('#purchase-form').validator({
+ custom: {
+ 'isodate': function($el)
+ {
+ if ($el.val().length !== 0 && !moment($el.val(), 'YYYY-MM-DD', true).isValid())
+ {
+ return 'Wrong date format, needs to be YYYY-MM-DD';
+ }
+ else if (moment($el.val()).isValid())
+ {
+ if (moment($el.val()).isBefore(moment(), 'day'))
+ {
+ return 'This value cannot be before today.';
+ }
+ }
+ }
+ }
+});
+$('#purchase-form').validator('validate');
+
+$('#best_before_date').on('focus', function(e)
+{
+ if ($('#product_id_text_input').val().length === 0)
+ {
+ $('#product_id_text_input').focus();
+ }
+});
+
+$('#amount').on('focus', function(e)
+{
+ if ($('#product_id_text_input').val().length === 0)
+ {
+ $('#product_id_text_input').focus();
+ }
+ else
+ {
+ $(this).select();
+ }
+});
+
+$('#purchase-form input').keydown(function(event)
+{
+ if (event.keyCode === 13) //Enter
+ {
+ if ($('#purchase-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
+ {
+ event.preventDefault();
+ return false;
+ }
+ }
+});
+
+var prefillProduct = GetUriParam('createdproduct');
+if (prefillProduct !== undefined)
+{
+ var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + prefillProduct + "']").first();
+ if (possibleOptionElement.length === 0)
+ {
+ possibleOptionElement = $("#product_id option:contains('" + prefillProduct + "')").first();
+ }
+
+ if (possibleOptionElement.length > 0)
+ {
+ $('#product_id').val(possibleOptionElement.val());
+ $('#product_id').data('combobox').refresh();
+ $('#product_id').trigger('change');
+ $('#best_before_date').focus();
+ }
+}
+
+var addBarcode = GetUriParam('addbarcodetoselection');
+if (addBarcode !== undefined)
+{
+ $('#addbarcodetoselection').text(addBarcode);
+ $('#flow-info-addbarcodetoselection').removeClass('hide');
+ $('#barcode-lookup-disabled-hint').removeClass('hide');
+}
+
$('#best_before_date').on('change', function(e)
{
$('#purchase-form').validator('validate');
diff --git a/public/viewjs/quantityunitform.js b/public/viewjs/quantityunitform.js
index 488efa4d..c81df2fa 100644
--- a/public/viewjs/quantityunitform.js
+++ b/public/viewjs/quantityunitform.js
@@ -30,9 +30,6 @@
}
});
-$(function()
-{
- $('#name').focus();
- $('#quantityunit-form').validator();
- $('#quantityunit-form').validator('validate');
-});
+$('#name').focus();
+$('#quantityunit-form').validator();
+$('#quantityunit-form').validator('validate');
diff --git a/public/viewjs/quantityunits.js b/public/viewjs/quantityunits.js
index 587ea855..6463bd8d 100644
--- a/public/viewjs/quantityunits.js
+++ b/public/viewjs/quantityunits.js
@@ -31,13 +31,11 @@
});
});
-$(function()
-{
- $('#quantityunits-table').DataTable({
- 'pageLength': 50,
- 'order': [[1, 'asc']],
- 'columnDefs': [
- { 'orderable': false, 'targets': 0 }
- ]
- });
+$('#quantityunits-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[1, 'asc']],
+ 'columnDefs': [
+ { 'orderable': false, 'targets': 0 }
+ ],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/public/viewjs/shoppinglist.js b/public/viewjs/shoppinglist.js
index 198d17c7..7ecd5549 100644
--- a/public/viewjs/shoppinglist.js
+++ b/public/viewjs/shoppinglist.js
@@ -26,13 +26,11 @@ $(document).on('click', '#add-products-below-min-stock-amount', function(e)
);
});
-$(function()
-{
- $('#shoppinglist-table').DataTable({
- 'pageLength': 50,
- 'order': [[1, 'asc']],
- 'columnDefs': [
- { 'orderable': false, 'targets': 0 }
- ]
- });
+$('#shoppinglist-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[1, 'asc']],
+ 'columnDefs': [
+ { 'orderable': false, 'targets': 0 }
+ ],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/public/viewjs/shoppinglistform.js b/public/viewjs/shoppinglistform.js
index 4d20eb62..2ba8bb7f 100644
--- a/public/viewjs/shoppinglistform.js
+++ b/public/viewjs/shoppinglistform.js
@@ -36,22 +36,13 @@ $('#product_id').on('change', function(e)
if (productId)
{
+ Grocy.Components.ProductCard.Refresh(productId);
+
Grocy.FetchJson('/api/stock/get-product-details/' + productId,
function (productDetails)
{
- $('#selected-product-name').text(productDetails.product.name);
- $('#selected-product-stock-amount').text(productDetails.stock_amount || '0');
- $('#selected-product-stock-qu-name').text(productDetails.quantity_unit_stock.name);
- $('#selected-product-stock-qu-name2').text(productDetails.quantity_unit_stock.name);
- $('#selected-product-last-purchased').text((productDetails.last_purchased || 'never').substring(0, 10));
- $('#selected-product-last-purchased-timeago').text($.timeago(productDetails.last_purchased || ''));
- $('#selected-product-last-used').text((productDetails.last_used || 'never').substring(0, 10));
- $('#selected-product-last-used-timeago').text($.timeago(productDetails.last_used || ''));
$('#amount_qu_unit').text(productDetails.quantity_unit_purchase.name);
- EmptyElementWhenMatches('#selected-product-last-purchased-timeago', 'NaN years ago');
- EmptyElementWhenMatches('#selected-product-last-used-timeago', 'NaN years ago');
-
if ($('#product_id').hasClass('suppress-next-custom-validate-event'))
{
$('#product_id').removeClass('suppress-next-custom-validate-event');
@@ -97,53 +88,50 @@ $('#product_id').on('change', function(e)
}
});
-$(function()
+$('.combobox').combobox({
+ appendId: '_text_input'
+});
+
+$('#product_id_text_input').on('change', function(e)
{
- $('.combobox').combobox({
- appendId: '_text_input'
- });
+ var input = $('#product_id_text_input').val().toString();
+ var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
- $('#product_id_text_input').on('change', function(e)
- {
- var input = $('#product_id_text_input').val().toString();
- var possibleOptionElement = $("#product_id option[data-additional-searchdata*='" + input + "']").first();
-
- if (possibleOptionElement.length > 0 && possibleOptionElement.text().length > 0) {
- $('#product_id').val(possibleOptionElement.val());
- $('#product_id').data('combobox').refresh();
- $('#product_id').trigger('change');
- }
- });
-
- $('#product_id_text_input').focus();
- $('#product_id_text_input').trigger('change');
-
- if (Grocy.EditMode === 'edit')
- {
- $('#product_id').addClass('suppress-next-custom-validate-event');
+ if (possibleOptionElement.length > 0 && possibleOptionElement.text().length > 0) {
+ $('#product_id').val(possibleOptionElement.val());
+ $('#product_id').data('combobox').refresh();
$('#product_id').trigger('change');
}
-
- $('#shoppinglist-form').validator();
- $('#shoppinglist-form').validator('validate');
-
- $('#amount').on('focus', function(e)
- {
- if ($('#product_id_text_input').val().length === 0)
- {
- $('#product_id_text_input').focus();
- }
- });
-
- $('#shoppinglist-form input').keydown(function(event)
- {
- if (event.keyCode === 13) //Enter
- {
- if ($('#shoppinglist-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
- {
- event.preventDefault();
- return false;
- }
- }
- });
+});
+
+$('#product_id_text_input').focus();
+$('#product_id_text_input').trigger('change');
+
+if (Grocy.EditMode === 'edit')
+{
+ $('#product_id').addClass('suppress-next-custom-validate-event');
+ $('#product_id').trigger('change');
+}
+
+$('#shoppinglist-form').validator();
+$('#shoppinglist-form').validator('validate');
+
+$('#amount').on('focus', function(e)
+{
+ if ($('#product_id_text_input').val().length === 0)
+ {
+ $('#product_id_text_input').focus();
+ }
+});
+
+$('#shoppinglist-form input').keydown(function(event)
+{
+ if (event.keyCode === 13) //Enter
+ {
+ if ($('#shoppinglist-form').validator('validate').has('.has-error').length !== 0) //There is at least one validation error
+ {
+ event.preventDefault();
+ return false;
+ }
+ }
});
diff --git a/public/viewjs/stockoverview.js b/public/viewjs/stockoverview.js
index c5825bbf..e7922127 100644
--- a/public/viewjs/stockoverview.js
+++ b/public/viewjs/stockoverview.js
@@ -1,7 +1,5 @@
-$(function()
-{
- $('#stock-overview-table').DataTable({
- 'pageLength': 50,
- 'order': [[2, 'asc']]
- });
+$('#stock-overview-table').DataTable({
+ 'pageLength': 50,
+ 'order': [[2, 'asc']],
+ 'language': JSON.parse(L('datatables_localization'))
});
diff --git a/services/DemoDataGeneratorService.php b/services/DemoDataGeneratorService.php
index 156c0e48..1715b29f 100644
--- a/services/DemoDataGeneratorService.php
+++ b/services/DemoDataGeneratorService.php
@@ -2,47 +2,52 @@
namespace Grocy\Services;
+use \Grocy\Services\LocalizationService;
+
class DemoDataGeneratorService extends BaseService
{
public function PopulateDemoData()
{
+ $localizationService = new LocalizationService(CULTURE);
+
$rowCount = $this->DatabaseService->ExecuteDbQuery('SELECT COUNT(*) FROM migrations WHERE migration = -1')->fetchColumn();
if (intval($rowCount) === 0)
{
$sql = "
- UPDATE locations SET name = 'Vorratskammer', description = '' WHERE id = 1;
- INSERT INTO locations (name) VALUES ('Süßigkeitenschrank'); --2
- INSERT INTO locations (name) VALUES ('Konservenschrank'); --3
- INSERT INTO locations (name) VALUES ('Kühlschrank'); --4
+ INSERT INTO locations (name) VALUES ('{$localizationService->Localize('Pantry')}'); --2
+ INSERT INTO locations (name) VALUES ('{$localizationService->Localize('Candy cupboard')}'); --3
+ INSERT INTO locations (name) VALUES ('{$localizationService->Localize('Tinned food cupboard')}'); --4
+ INSERT INTO locations (name) VALUES ('{$localizationService->Localize('Fridge')}'); --5
- UPDATE quantity_units SET name = 'Stück' WHERE id = 1;
- INSERT INTO quantity_units (name) VALUES ('Packung'); --2
- INSERT INTO quantity_units (name) VALUES ('Glas'); --3
- INSERT INTO quantity_units (name) VALUES ('Dose'); --4
- INSERT INTO quantity_units (name) VALUES ('Becher'); --5
- INSERT INTO quantity_units (name) VALUES ('Bund'); --6
+ INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Piece')}'); --2
+ INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Pack')}'); --3
+ INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Glass')}'); --4
+ INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Tin')}'); --5
+ INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Can')}'); --6
+ INSERT INTO quantity_units (name) VALUES ('{$localizationService->Localize('Bunch')}'); --7
- DELETE FROM products WHERE id IN (1, 2);
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('Gummibärchen', 2, 2, 2, 1, 8); --3
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('Chips', 2, 2, 2, 1, 10); --4
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Eier', 1, 2, 1, 10); --5
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Nudeln', 1, 2, 2, 1); --6
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Essiggurken', 3, 3, 3, 1); --7
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Gulaschsuppe', 3, 4, 4, 1); --8
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Joghurt', 4, 5, 5, 1); --9
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Käse', 4, 2, 2, 1); --10
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Aufschnitt', 4, 2, 2, 1); --11
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Paprika', 4, 1, 1, 1); --12
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Gurke', 4, 1, 1, 1); --13
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Radieschen', 4, 6, 6, 1); --14
- INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('Tomate', 4, 1, 1, 1); --15
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('{$localizationService->Localize('Cookies')}', 3, 3, 3, 1, 8); --1
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('{$localizationService->Localize('Chocolate')}', 3, 3, 3, 1, 8); --2
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('{$localizationService->Localize('Gummy bears')}', 3, 3, 3, 1, 8); --3
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock, min_stock_amount) VALUES ('{$localizationService->Localize('Crisps')}', 3, 3, 3, 1, 10); --4
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Eggs')}', 5, 3, 2, 10); --5
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Noodles')}', 3, 3, 3, 1); --6
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Pickles')}', 4,4, 4, 1); --7
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Gulash soup')}', 4, 5, 5, 1); --8
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Yogurt')}', 5, 6, 6, 1); --9
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Cheese')}', 5, 3, 3, 1); --10
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Cold cuts')}', 5, 3, 3, 1); --11
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Paprika')}', 5, 2, 2, 1); --12
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Cucumber')}', 5, 2, 2, 1); --13
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Radish')}', 5, 7, 7, 1); --14
+ INSERT INTO products (name, location_id, qu_id_purchase, qu_id_stock, qu_factor_purchase_to_stock) VALUES ('{$localizationService->Localize('Tomato')}', 5, 2, 2, 1); --15
- INSERT INTO habits (name, period_type, period_days) VALUES ('Changed towels in the bathroom', 'manually', 5); --1
- INSERT INTO habits (name, period_type, period_days) VALUES ('Cleaned the kitchen floor', 'dynamic-regular', 7); --2
+ INSERT INTO habits (name, period_type, period_days) VALUES ('{$localizationService->Localize('Changed towels in the bathroom')}', 'manually', 5); --1
+ INSERT INTO habits (name, period_type, period_days) VALUES ('{$localizationService->Localize('Cleaned the kitchen floor')}', 'dynamic-regular', 7); --2
- INSERT INTO batteries (name, description, used_in) VALUES ('Battery1', 'Warranty ends 2022', 'TV remote control'); --1
- INSERT INTO batteries (name, description, used_in) VALUES ('Battery2', 'Warranty ends 2022', 'Alarm clock'); --2
- INSERT INTO batteries (name, description, used_in, charge_interval_days) VALUES ('Battery3', 'Warranty ends 2022', 'Heat remote control', 60); --3
+ INSERT INTO batteries (name, description, used_in) VALUES ('{$localizationService->Localize('Battery')}1', '{$localizationService->Localize('Warranty ends')} 2023', '{$localizationService->Localize('TV remote control')}'); --1
+ INSERT INTO batteries (name, description, used_in) VALUES ('{$localizationService->Localize('Battery')}2', '{$localizationService->Localize('Warranty ends')} 2022', '{$localizationService->Localize('Alarm clock')}'); --2
+ INSERT INTO batteries (name, description, used_in, charge_interval_days) VALUES ('{$localizationService->Localize('Battery')}3', '{$localizationService->Localize('Warranty ends')} 2022', '{$localizationService->Localize('Heat remote control')}', 60); --3
INSERT INTO migrations (migration) VALUES (-1);
";
diff --git a/services/LocalizationService.php b/services/LocalizationService.php
new file mode 100644
index 00000000..56e81d27
--- /dev/null
+++ b/services/LocalizationService.php
@@ -0,0 +1,103 @@
+Culture = $culture;
+
+ $this->StringsDefaultCulture = $this->LoadLocalizationFile(self::DEFAULT_CULTURE);
+ $this->StringsCurrentCulture = $this->LoadLocalizationFile($culture);
+ $this->StringsMerged = array_merge($this->StringsDefaultCulture, $this->StringsCurrentCulture);
+ }
+
+ protected $Culture;
+ protected $StringsDefaultCulture;
+ protected $StringsCurrentCulture;
+ protected $StringsMerged;
+
+ private function LoadLocalizationFile(string $culture)
+ {
+ $file = __DIR__ . "/../localization/$culture.php";
+
+ if (file_exists($file))
+ {
+ return require $file;
+ }
+ else
+ {
+ return array();
+ }
+ }
+
+ private function LogMissingLocalization(string $culture, string $text)
+ {
+ $file = __DIR__ . "/../data/missing_translations_$culture.json";
+
+ $missingTranslations = array();
+ if (file_exists($file))
+ {
+ $missingTranslations = json_decode(file_get_contents($file), true);
+ }
+
+ if (!array_key_exists($text, $missingTranslations))
+ {
+ $missingTranslations[$text] = '#TranslationMissing#';
+ }
+
+ if (count($missingTranslations) > 0)
+ {
+ file_put_contents($file, json_encode($missingTranslations, JSON_PRETTY_PRINT));
+ }
+ }
+
+ public function Localize(string $text, ...$placeholderValues)
+ {
+ if (MODE === 'dev')
+ {
+ if (!array_key_exists($text, $this->StringsDefaultCulture))
+ {
+ $this->LogMissingLocalization(self::DEFAULT_CULTURE, $text);
+ }
+
+ if (!array_key_exists($text, $this->StringsCurrentCulture))
+ {
+ $this->LogMissingLocalization($this->Culture, $text);
+ }
+ }
+
+ $localizedText = $text;
+ if (array_key_exists($text, $this->StringsMerged))
+ {
+ $localizedText = $this->StringsMerged[$text];
+ }
+
+ for ($i = 0; $i < count($placeholderValues); $i++)
+ {
+ $localizedText = str_replace('#' . ($i + 1), $placeholderValues[$i], $localizedText);
+ }
+
+ return $localizedText;
+ }
+
+ public function GetLocalizations()
+ {
+ return $this->StringsMerged;
+ }
+
+ public function GetDefaultCultureLocalizations()
+ {
+ return $this->StringsDefaultCulture;
+ }
+
+ public function GetCurrentCultureLocalizations()
+ {
+ return $this->StringsCurrentCulture;
+ }
+}
diff --git a/version.txt b/version.txt
index bd8bf882..27f9cd32 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-1.7.0
+1.8.0
diff --git a/views/batteries.blade.php b/views/batteries.blade.php
index bb7d26a1..df484c89 100644
--- a/views/batteries.blade.php
+++ b/views/batteries.blade.php
@@ -1,6 +1,6 @@
@extends('layout.default')
-@section('title', 'Batteries')
+@section('title', $L('Batteries'))
@section('activeNav', 'batteries')
@section('viewJsName', 'batteries')
@@ -8,9 +8,9 @@
Battery | -Last charged | -Next planned charge cycle | +{{ $L('Battery') }} | +{{ $L('Last charged') }} | +{{ $L('Next planned charge cycle') }} |
---|