Split application translation strings and QU strings (fixes #1705)

This commit is contained in:
Bernd Bestel 2022-02-06 21:09:34 +01:00
parent 28f7700dac
commit 12e5377c40
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
26 changed files with 81 additions and 58 deletions

View File

@ -11,6 +11,7 @@
- Fixed that when adding missing recipe ingredients, with the option "Only check if any amount is in stock" enabled, to the shopping list, unit conversions (if any) weren't considered - Fixed that when adding missing recipe ingredients, with the option "Only check if any amount is in stock" enabled, to the shopping list, unit conversions (if any) weren't considered
- Fixed that the recipe stock fulfillment information about shopping list amounts was not correct when the ingredient had a decimal amount - Fixed that the recipe stock fulfillment information about shopping list amounts was not correct when the ingredient had a decimal amount
- Fixed that the meal plan showed the total calories per recipe (instead of per serving as stated by the suffix) - Fixed that the meal plan showed the total calories per recipe (instead of per serving as stated by the suffix)
- Fixed that when having a quantity unit matching any application string, the translation of that string was used to display that unit
- Fixed that formatted (HTML) text for the (hidden by default) product description column on the stock overview page was not correctly displayed - Fixed that formatted (HTML) text for the (hidden by default) product description column on the stock overview page was not correctly displayed
- Fixed that numeric and date-time sorting of table columns on the stock entries page did not work correctly (thanks @MasterofJOKers) - Fixed that numeric and date-time sorting of table columns on the stock entries page did not work correctly (thanks @MasterofJOKers)
- Fixed that the barcode lookup for the "Stock by-barcode" API endpoints was case sensitive - Fixed that the barcode lookup for the "Stock by-barcode" API endpoints was case sensitive

View File

@ -126,10 +126,11 @@ class BaseController
$this->View->set('__t', function (string $text, ...$placeholderValues) use ($localizationService) { $this->View->set('__t', function (string $text, ...$placeholderValues) use ($localizationService) {
return $localizationService->__t($text, $placeholderValues); return $localizationService->__t($text, $placeholderValues);
}); });
$this->View->set('__n', function ($number, $singularForm, $pluralForm) use ($localizationService) { $this->View->set('__n', function ($number, $singularForm, $pluralForm, $isQu = false) use ($localizationService) {
return $localizationService->__n($number, $singularForm, $pluralForm); return $localizationService->__n($number, $singularForm, $pluralForm, $isQu);
}); });
$this->View->set('LocalizationStrings', $localizationService->GetPoAsJsonString()); $this->View->set('LocalizationStrings', $localizationService->GetPoAsJsonString());
$this->View->set('LocalizationStringsQu', $localizationService->GetPoAsJsonStringQu());
// TODO: Better handle this generically based on the current language (header in .po file?) // TODO: Better handle this generically based on the current language (header in .po file?)
$dir = 'ltr'; $dir = 'ltr';

View File

@ -232,6 +232,7 @@ U = function(relativePath)
} }
Grocy.Translator = new Translator(Grocy.LocalizationStrings); Grocy.Translator = new Translator(Grocy.LocalizationStrings);
Grocy.TranslatorQu = new Translator(Grocy.LocalizationStringsQu);
__t = function(text, ...placeholderValues) __t = function(text, ...placeholderValues)
{ {
if (Grocy.Mode === "dev") if (Grocy.Mode === "dev")
@ -245,7 +246,7 @@ __t = function(text, ...placeholderValues)
return Grocy.Translator.__(text, ...placeholderValues) return Grocy.Translator.__(text, ...placeholderValues)
} }
__n = function(number, singularForm, pluralForm) __n = function(number, singularForm, pluralForm, isQu = false)
{ {
if (Grocy.Mode === "dev") if (Grocy.Mode === "dev")
{ {
@ -256,8 +257,15 @@ __n = function(number, singularForm, pluralForm)
} }
} }
if (isQu)
{
return Grocy.TranslatorQu.n__(singularForm, pluralForm, Math.abs(number), Math.abs(number))
}
else
{
return Grocy.Translator.n__(singularForm, pluralForm, Math.abs(number), Math.abs(number)) return Grocy.Translator.n__(singularForm, pluralForm, Math.abs(number), Math.abs(number))
} }
}
if (!Grocy.ActiveNav.isEmpty()) if (!Grocy.ActiveNav.isEmpty())
{ {

View File

@ -94,7 +94,7 @@ $(".input-group-productamountpicker").on("change", function()
var quFactor = $("#qu_id option:selected").attr("data-qu-factor"); var quFactor = $("#qu_id option:selected").attr("data-qu-factor");
var amount = $("#display_amount").val(); var amount = $("#display_amount").val();
var destinationAmount = amount / quFactor; var destinationAmount = amount / quFactor;
var destinationQuName = __n(destinationAmount, $("#qu_id").attr("data-destination-qu-name"), $("#qu_id").attr("data-destination-qu-name-plural")) var destinationQuName = __n(destinationAmount, $("#qu_id").attr("data-destination-qu-name"), $("#qu_id").attr("data-destination-qu-name-plural"), true);
if ($("#qu_id").attr("data-destination-qu-name") == selectedQuName || Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled || amount.toString().isEmpty() || selectedQuName.toString().isEmpty()) if ($("#qu_id").attr("data-destination-qu-name") == selectedQuName || Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled || amount.toString().isEmpty() || selectedQuName.toString().isEmpty())
{ {

View File

@ -11,7 +11,7 @@ Grocy.Components.ProductCard.Refresh = function(productId)
$('#productcard-product-name').text(productDetails.product.name); $('#productcard-product-name').text(productDetails.product.name);
$('#productcard-product-description').html(productDetails.product.description); $('#productcard-product-description').html(productDetails.product.description);
$('#productcard-product-stock-amount').text(stockAmount); $('#productcard-product-stock-amount').text(stockAmount);
$('#productcard-product-stock-qu-name').text(__n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural)); $('#productcard-product-stock-qu-name').text(__n(stockAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true));
$('#productcard-product-stock-value').text(stockValue + ' ' + Grocy.Currency); $('#productcard-product-stock-value').text(stockValue + ' ' + Grocy.Currency);
$('#productcard-product-last-purchased').text((productDetails.last_purchased || '2999-12-31').substring(0, 10)); $('#productcard-product-last-purchased').text((productDetails.last_purchased || '2999-12-31').substring(0, 10));
$('#productcard-product-last-purchased-timeago').attr("datetime", productDetails.last_purchased || '2999-12-31'); $('#productcard-product-last-purchased-timeago').attr("datetime", productDetails.last_purchased || '2999-12-31');
@ -26,7 +26,7 @@ Grocy.Components.ProductCard.Refresh = function(productId)
if (productDetails.is_aggregated_amount == 1) if (productDetails.is_aggregated_amount == 1)
{ {
$('#productcard-product-stock-amount-aggregated').text(productDetails.stock_amount_aggregated); $('#productcard-product-stock-amount-aggregated').text(productDetails.stock_amount_aggregated);
$('#productcard-product-stock-qu-name-aggregated').text(__n(productDetails.stock_amount_aggregated, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural)); $('#productcard-product-stock-qu-name-aggregated').text(__n(productDetails.stock_amount_aggregated, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true));
if (productDetails.stock_amount_opened_aggregated > 0) if (productDetails.stock_amount_opened_aggregated > 0)
{ {

View File

@ -77,11 +77,11 @@
if (productDetails.product.enable_tare_weight_handling == 1 && !jsonData.exact_amount) if (productDetails.product.enable_tare_weight_handling == 1 && !jsonData.exact_amount)
{ {
var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount - (parseFloat(productDetails.product.tare_weight) + parseFloat(productDetails.stock_amount))) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount - (parseFloat(productDetails.product.tare_weight) + parseFloat(productDetails.stock_amount))) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
} }
else else
{ {
var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var successMessage = __t('Removed %1$s of %2$s from stock', Math.abs(jsonForm.amount) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
} }
if (GetUriParam("embedded") !== undefined) if (GetUriParam("embedded") !== undefined)
@ -177,7 +177,7 @@ $('#save-mark-as-open-button').on('click', function(e)
} }
Grocy.FrontendHelpers.EndUiBusy("consume-form"); Grocy.FrontendHelpers.EndUiBusy("consume-form");
toastr.success(__t('Marked %1$s of %2$s as opened', parseFloat(jsonForm.amount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + result[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'); toastr.success(__t('Marked %1$s of %2$s as opened', parseFloat(jsonForm.amount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + result[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>');
if (BoolVal(Grocy.UserSettings.stock_default_consume_amount_use_quick_consume_amount)) if (BoolVal(Grocy.UserSettings.stock_default_consume_amount_use_quick_consume_amount))
{ {

View File

@ -114,7 +114,7 @@
Grocy.Api.Get('stock/products/' + jsonForm.product_id, Grocy.Api.Get('stock/products/' + jsonForm.product_id,
function(result) function(result)
{ {
var successMessage = __t('Stock amount of %1$s is now %2$s', result.product.name, result.stock_amount + " " + __n(result.stock_amount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural)) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var successMessage = __t('Stock amount of %1$s is now %2$s', result.product.name, result.stock_amount + " " + __n(result.stock_amount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true)) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
if (GetUriParam("embedded") !== undefined) if (GetUriParam("embedded") !== undefined)
{ {
@ -384,7 +384,7 @@ $('#display_amount').on('keyup', function(e)
} }
else if (newAmount > productStockAmount + containerWeight) else if (newAmount > productStockAmount + containerWeight)
{ {
$('#inventory-change-info').text(__t('This means %s will be added to stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural))); $('#inventory-change-info').text(__t('This means %s will be added to stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true)));
Grocy.Components.DateTimePicker.GetInputElement().attr('required', ''); Grocy.Components.DateTimePicker.GetInputElement().attr('required', '');
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
{ {
@ -393,7 +393,7 @@ $('#display_amount').on('keyup', function(e)
} }
else if (newAmount < productStockAmount + containerWeight) else if (newAmount < productStockAmount + containerWeight)
{ {
$('#inventory-change-info').text(__t('This means %s will be removed from stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural))); $('#inventory-change-info').text(__t('This means %s will be removed from stock', estimatedBookingAmount.toLocaleString() + ' ' + __n(estimatedBookingAmount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true)));
Grocy.Components.DateTimePicker.GetInputElement().removeAttr('required'); Grocy.Components.DateTimePicker.GetInputElement().removeAttr('required');
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING)
{ {

View File

@ -252,13 +252,13 @@ $(".calendar").each(function()
element.html('\ element.html('\
<div> \ <div> \
<h5 class="text-truncate mb-1 cursor-link display-product-button ' + additionalTitleCssClasses + '" data-toggle="tooltip" title="' + __t("Display product") + '" data-product-id="' + productDetails.product.id.toString() + '">' + productDetails.product.name + '</h5> \ <h5 class="text-truncate mb-1 cursor-link display-product-button ' + additionalTitleCssClasses + '" data-toggle="tooltip" title="' + __t("Display product") + '" data-product-id="' + productDetails.product.id.toString() + '">' + productDetails.product.name + '</h5> \
<h5 class="small text-truncate mb-1"><span class="locale-number locale-number-quantity-amount">' + mealPlanEntry.product_amount + "</span> " + __n(mealPlanEntry.product_amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural) + '</h5> \ <h5 class="small text-truncate mb-1"><span class="locale-number locale-number-quantity-amount">' + mealPlanEntry.product_amount + "</span> " + __n(mealPlanEntry.product_amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true) + '</h5> \
<h5 class="small timeago-contextual text-truncate mb-1">' + fulfillmentIconHtml + " " + fulfillmentInfoHtml + '</h5> \ <h5 class="small timeago-contextual text-truncate mb-1">' + fulfillmentIconHtml + " " + fulfillmentInfoHtml + '</h5> \
' + costsAndCaloriesPerServing + ' \ ' + costsAndCaloriesPerServing + ' \
<h5 class="d-print-none"> \ <h5 class="d-print-none"> \
<a class="ml-1 btn btn-outline-danger btn-xs remove-product-button" href="#" data-toggle="tooltip" title="' + __t("Delete this item") + '"><i class="fas fa-trash"></i></a> \ <a class="ml-1 btn btn-outline-danger btn-xs remove-product-button" href="#" data-toggle="tooltip" title="' + __t("Delete this item") + '"><i class="fas fa-trash"></i></a> \
<a class="btn btn-outline-info btn-xs edit-meal-plan-entry-button" href="#" data-toggle="tooltip" title="' + __t("Edit this item") + '"><i class="fas fa-edit"></i></a> \ <a class="btn btn-outline-info btn-xs edit-meal-plan-entry-button" href="#" data-toggle="tooltip" title="' + __t("Edit this item") + '"><i class="fas fa-edit"></i></a> \
<a class="ml-1 btn btn-outline-success btn-xs product-consume-button ' + productConsumeButtonDisabledClasses + '" href="#" data-toggle="tooltip" title="' + __t("Consume %1$s of %2$s", parseFloat(mealPlanEntry.product_amount).toLocaleString() + ' ' + __n(mealPlanEntry.product_amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name) + '" data-product-id="' + productDetails.product.id.toString() + '" data-product-name="' + productDetails.product.name + '" data-product-amount="' + mealPlanEntry.product_amount + '" data-mealplan-entry-id="' + mealPlanEntry.id.toString() + '"><i class="fas fa-utensils"></i></a> \ <a class="ml-1 btn btn-outline-success btn-xs product-consume-button ' + productConsumeButtonDisabledClasses + '" href="#" data-toggle="tooltip" title="' + __t("Consume %1$s of %2$s", parseFloat(mealPlanEntry.product_amount).toLocaleString() + ' ' + __n(mealPlanEntry.product_amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '" data-product-id="' + productDetails.product.id.toString() + '" data-product-name="' + productDetails.product.name + '" data-product-amount="' + mealPlanEntry.product_amount + '" data-mealplan-entry-id="' + mealPlanEntry.id.toString() + '"><i class="fas fa-utensils"></i></a> \
' + shoppingListButtonHtml + ' \ ' + shoppingListButtonHtml + ' \
' + doneButtonHtml + ' \ ' + doneButtonHtml + ' \
</h5> \ </h5> \
@ -800,7 +800,7 @@ $(document).on('click', '.product-consume-button', function(e)
Grocy.Api.Get('stock/products/' + productId, Grocy.Api.Get('stock/products/' + productId,
function(result) function(result)
{ {
var toastMessage = __t('Removed %1$s of %2$s from stock', consumeAmount.toString() + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var toastMessage = __t('Removed %1$s of %2$s from stock', consumeAmount.toString() + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
Grocy.Api.Put('objects/meal_plan/' + mealPlanEntryId, { "done": 1 }, Grocy.Api.Put('objects/meal_plan/' + mealPlanEntryId, { "done": 1 },
function(result) function(result)

View File

@ -177,7 +177,7 @@ $('.input-group-qu').on('change', function(e)
if (factor > 1 || quIdPurchase != quIdStock) if (factor > 1 || quIdPurchase != quIdStock)
{ {
$('#qu-conversion-info').text(__t('This means 1 %1$s purchased will be converted into %2$s %3$s in stock', $("#qu_id_purchase option:selected").text(), (1 * factor).toString(), __n((1 * factor).toString(), $("#qu_id_stock option:selected").text(), $("#qu_id_stock option:selected").data("plural-form")))); $('#qu-conversion-info').text(__t('This means 1 %1$s purchased will be converted into %2$s %3$s in stock', $("#qu_id_purchase option:selected").text(), (1 * factor).toString(), __n((1 * factor).toString(), $("#qu_id_stock option:selected").text(), $("#qu_id_stock option:selected").data("plural-form"), true)));
$('#qu-conversion-info').removeClass('d-none'); $('#qu-conversion-info').removeClass('d-none');
} }
else else

View File

@ -115,7 +115,7 @@ $('#save-purchase-button').on('click', function(e)
{ {
amountMessage = parseFloat(jsonForm.amount) - parseFloat(productDetails.stock_amount) - parseFloat(productDetails.product.tare_weight); amountMessage = parseFloat(jsonForm.amount) - parseFloat(productDetails.stock_amount) - parseFloat(productDetails.product.tare_weight);
} }
var successMessage = __t('Added %1$s of %2$s to stock', amountMessage + " " + __n(amountMessage, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + result[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var successMessage = __t('Added %1$s of %2$s to stock', amountMessage + " " + __n(amountMessage, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + result[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER) if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_LABEL_PRINTER)
{ {

View File

@ -179,12 +179,12 @@ $('.input-group-qu').on('change', function(e)
if (fromQuId && toQuId) if (fromQuId && toQuId)
{ {
$('#qu-conversion-info').text(__t('This means 1 %1$s is the same as %2$s %3$s', $("#from_qu_id option:selected").text(), parseFloat((1 * factor)).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }), __n((1 * factor).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }), $("#to_qu_id option:selected").text(), $("#to_qu_id option:selected").data("plural-form")))); $('#qu-conversion-info').text(__t('This means 1 %1$s is the same as %2$s %3$s', $("#from_qu_id option:selected").text(), parseFloat((1 * factor)).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }), __n((1 * factor).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }), $("#to_qu_id option:selected").text(), $("#to_qu_id option:selected").data("plural-form"), true)));
$('#qu-conversion-info').removeClass('d-none'); $('#qu-conversion-info').removeClass('d-none');
if (Grocy.EditMode === 'create') if (Grocy.EditMode === 'create')
{ {
$('#qu-conversion-inverse-info').text(__t('This means 1 %1$s is the same as %2$s %3$s', $("#to_qu_id option:selected").text(), parseFloat((1 / factor)).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }), __n((1 / factor).toString(), $("#from_qu_id option:selected").text(), $("#from_qu_id option:selected").data("plural-form")))); $('#qu-conversion-inverse-info').text(__t('This means 1 %1$s is the same as %2$s %3$s', $("#to_qu_id option:selected").text(), parseFloat((1 / factor)).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }), __n((1 / factor).toString(), $("#from_qu_id option:selected").text(), $("#from_qu_id option:selected").data("plural-form"), true)));
$('#qu-conversion-inverse-info').removeClass('d-none'); $('#qu-conversion-inverse-info').removeClass('d-none');
} }
} }

View File

@ -25,7 +25,7 @@ function RefreshQuPluralTestingResult()
} }
animateCSS("h2", "shake"); animateCSS("h2", "shake");
$("#result").text(__n(amount, singularForm, pluralForm)); $("#result").text(__n(amount, singularForm, pluralForm, true));
} }
if (GetUriParam("qu") !== undefined) if (GetUriParam("qu") !== undefined)

View File

@ -59,7 +59,7 @@ $('#save-shoppinglist-button').on('click', function(e)
Grocy.Api.Get('stock/products/' + jsonData.product_id, Grocy.Api.Get('stock/products/' + jsonData.product_id,
function(productDetails) function(productDetails)
{ {
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural")), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
}, },
@ -96,7 +96,7 @@ $('#save-shoppinglist-button').on('click', function(e)
Grocy.Api.Get('stock/products/' + jsonData.product_id, Grocy.Api.Get('stock/products/' + jsonData.product_id,
function(productDetails) function(productDetails)
{ {
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural")), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
}, },
@ -138,7 +138,7 @@ $('#save-shoppinglist-button').on('click', function(e)
Grocy.Api.Get('stock/products/' + jsonData.product_id, Grocy.Api.Get('stock/products/' + jsonData.product_id,
function(productDetails) function(productDetails)
{ {
window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural")), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("ShowSuccessMessage", __t("Added %1$s of %2$s to the shopping list \"%3$s\"", displayAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(displayAmount, $("#qu_id option:selected").text(), $("#qu_id option:selected").attr("data-qu-name-plural"), true), productDetails.product.name, $("#shopping_list_id option:selected").text())), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("ShoppingListChanged", $("#shopping_list_id").val().toString()), Grocy.BaseUrl);
window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl); window.parent.postMessage(WindowMessageBag("CloseAllModals"), Grocy.BaseUrl);
}, },

View File

@ -67,7 +67,7 @@ $(document).on('click', '.stock-consume-button', function(e)
Grocy.Api.Get('stock/products/' + productId, Grocy.Api.Get('stock/products/' + productId,
function(result) function(result)
{ {
var toastMessage = __t('Removed %1$s of %2$s from stock', parseFloat(consumeAmount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockBookingEntry(' + bookingResponse[0].id + ',' + stockRowId + ')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var toastMessage = __t('Removed %1$s of %2$s from stock', parseFloat(consumeAmount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockBookingEntry(' + bookingResponse[0].id + ',' + stockRowId + ')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
if (wasSpoiled) if (wasSpoiled)
{ {
toastMessage += " (" + __t("Spoiled") + ")"; toastMessage += " (" + __t("Spoiled") + ")";

View File

@ -145,11 +145,11 @@ $(document).on('click', '.product-consume-button', function(e)
{ {
if (result.product.enable_tare_weight_handling == 1) if (result.product.enable_tare_weight_handling == 1)
{ {
var toastMessage = __t('Removed %1$s of %2$s from stock', parseFloat(originalTotalStockAmount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var toastMessage = __t('Removed %1$s of %2$s from stock', parseFloat(originalTotalStockAmount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
} }
else else
{ {
var toastMessage = __t('Removed %1$s of %2$s from stock', parseFloat(consumeAmount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var toastMessage = __t('Removed %1$s of %2$s from stock', parseFloat(consumeAmount).toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }) + " " + __n(consumeAmount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true), result.product.name) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
} }
if (wasSpoiled) if (wasSpoiled)
@ -328,7 +328,7 @@ function RefreshProductRow(productId)
{ {
animateCSS("#product-" + productId + "-row td:not(:first)", "shake"); animateCSS("#product-" + productId + "-row td:not(:first)", "shake");
$('#product-' + productId + '-qu-name').text(__n(result.stock_amount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural)); $('#product-' + productId + '-qu-name').text(__n(result.stock_amount, result.quantity_unit_stock.name, result.quantity_unit_stock.name_plural, true));
$('#product-' + productId + '-amount').text(result.stock_amount); $('#product-' + productId + '-amount').text(result.stock_amount);
$('#product-' + productId + '-consume-all-button').attr('data-consume-amount', result.stock_amount); $('#product-' + productId + '-consume-all-button').attr('data-consume-amount', result.stock_amount);
$('#product-' + productId + '-value').text(result.stock_value); $('#product-' + productId + '-value').text(result.stock_value);

View File

@ -56,11 +56,11 @@
if (productDetails.product.enable_tare_weight_handling == 1) if (productDetails.product.enable_tare_weight_handling == 1)
{ {
var successMessage = __t('Transfered %1$s of %2$s from %3$s to %4$s', Math.abs(jsonForm.amount - parseFloat(productDetails.product.tare_weight)) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name, $('option:selected', "#location_id_from").text(), $('option:selected', "#location_id_to").text()) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var successMessage = __t('Transfered %1$s of %2$s from %3$s to %4$s', Math.abs(jsonForm.amount - parseFloat(productDetails.product.tare_weight)) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name, $('option:selected', "#location_id_from").text(), $('option:selected', "#location_id_to").text()) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
} }
else else
{ {
var successMessage = __t('Transfered %1$s of %2$s from %3$s to %4$s', Math.abs(jsonForm.amount) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural), productDetails.product.name, $('option:selected', "#location_id_from").text(), $('option:selected', "#location_id_to").text()) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>'; var successMessage = __t('Transfered %1$s of %2$s from %3$s to %4$s', Math.abs(jsonForm.amount) + " " + __n(jsonForm.amount, productDetails.quantity_unit_stock.name, productDetails.quantity_unit_stock.name_plural, true), productDetails.product.name, $('option:selected', "#location_id_from").text(), $('option:selected', "#location_id_to").text()) + '<br><a class="btn btn-secondary btn-sm mt-2" href="#" onclick="UndoStockTransaction(\'' + bookingResponse[0].transaction_id + '\')"><i class="fas fa-undo"></i> ' + __t("Undo") + '</a>';
} }
if (GetUriParam("embedded") !== undefined) if (GetUriParam("embedded") !== undefined)

View File

@ -17,21 +17,21 @@ class LocalizationService
protected $Po; protected $Po;
protected $PoUserStrings;
protected $Pot; protected $Pot;
protected $PotMain; protected $PotMain;
protected $Translator; protected $Translator;
protected $TranslatorQU;
private static $instanceMap = []; private static $instanceMap = [];
public function CheckAndAddMissingTranslationToPot($text) public function CheckAndAddMissingTranslationToPot($text)
{ {
if (GROCY_MODE === 'dev') if (GROCY_MODE === 'dev')
{ {
if ($this->Pot->find('', $text) === false && $this->PoUserStrings->find('', $text) === false && empty($text) === false) if ($this->Pot->find('', $text) === false && empty($text) === false)
{ {
$translation = new Translation('', $text); $translation = new Translation('', $text);
$this->PotMain[] = $translation; $this->PotMain[] = $translation;
@ -69,12 +69,24 @@ class LocalizationService
return $this->Po->toJsonString(); return $this->Po->toJsonString();
} }
public function __n($number, $singularForm, $pluralForm) public function GetPoAsJsonStringQu()
{
return $this->PoQu->toJsonString();
}
public function __n($number, $singularForm, $pluralForm, $isQu = false)
{ {
$this->CheckAndAddMissingTranslationToPot($singularForm); $this->CheckAndAddMissingTranslationToPot($singularForm);
if ($isQu)
{
return sprintf($this->TranslatorQU->ngettext($singularForm, $pluralForm, abs(floatval($number))), $number);
}
else
{
return sprintf($this->Translator->ngettext($singularForm, $pluralForm, abs(floatval($number))), $number); return sprintf($this->Translator->ngettext($singularForm, $pluralForm, abs(floatval($number))), $number);
} }
}
public function __t($text, ...$placeholderValues) public function __t($text, ...$placeholderValues)
{ {
@ -140,9 +152,6 @@ class LocalizationService
} }
} }
$this->PoUserStrings = new Translations();
$this->PoUserStrings->setDomain('grocy/userstrings');
$this->Po = Translations::fromPoFile(__DIR__ . "/../localization/$culture/strings.po"); $this->Po = Translations::fromPoFile(__DIR__ . "/../localization/$culture/strings.po");
if (file_exists(__DIR__ . "/../localization/$culture/chore_assignment_types.po")) if (file_exists(__DIR__ . "/../localization/$culture/chore_assignment_types.po"))
@ -185,6 +194,9 @@ class LocalizationService
$this->Po = $this->Po->mergeWith(Translations::fromPoFile(__DIR__ . "/../localization/$culture/demo_data.po")); $this->Po = $this->Po->mergeWith(Translations::fromPoFile(__DIR__ . "/../localization/$culture/demo_data.po"));
} }
$this->Translator = new Translator();
$this->Translator->loadTranslations($this->Po);
$quantityUnits = null; $quantityUnits = null;
try try
{ {
@ -197,6 +209,8 @@ class LocalizationService
if ($quantityUnits !== null) if ($quantityUnits !== null)
{ {
$this->PoQu = new Translations();
foreach ($quantityUnits as $quantityUnit) foreach ($quantityUnits as $quantityUnit)
{ {
$translation = new Translation('', $quantityUnit['name']); $translation = new Translation('', $quantityUnit['name']);
@ -204,13 +218,11 @@ class LocalizationService
$translation->setPlural($quantityUnit['name_plural']); $translation->setPlural($quantityUnit['name_plural']);
$translation->setPluralTranslations(preg_split('/\r\n|\r|\n/', $quantityUnit['plural_forms'])); $translation->setPluralTranslations(preg_split('/\r\n|\r|\n/', $quantityUnit['plural_forms']));
$this->PoUserStrings[] = $translation; $this->PoQu[] = $translation;
} }
$this->Po = $this->Po->mergeWith($this->PoUserStrings); $this->TranslatorQU = new Translator();
} $this->TranslatorQU->loadTranslations($this->PoQu);
};
$this->Translator = new Translator();
$this->Translator->loadTranslations($this->Po);
} }
} }

View File

@ -95,6 +95,7 @@
Grocy.CalendarFirstDayOfWeek = '{{ GROCY_CALENDAR_FIRST_DAY_OF_WEEK }}'; Grocy.CalendarFirstDayOfWeek = '{{ GROCY_CALENDAR_FIRST_DAY_OF_WEEK }}';
Grocy.CalendarShowWeekNumbers = {{ BoolToString(GROCY_CALENDAR_SHOW_WEEK_OF_YEAR) }}; Grocy.CalendarShowWeekNumbers = {{ BoolToString(GROCY_CALENDAR_SHOW_WEEK_OF_YEAR) }};
Grocy.LocalizationStrings = {!! $LocalizationStrings !!}; Grocy.LocalizationStrings = {!! $LocalizationStrings !!};
Grocy.LocalizationStringsQu = {!! $LocalizationStringsQu !!};
Grocy.FeatureFlags = {!! json_encode($featureFlags) !!}; Grocy.FeatureFlags = {!! json_encode($featureFlags) !!};
Grocy.Webhooks = { Grocy.Webhooks = {
@if(GROCY_FEATURE_FLAG_LABEL_PRINTER && !GROCY_LABEL_PRINTER_RUN_SERVER) @if(GROCY_FEATURE_FLAG_LABEL_PRINTER && !GROCY_LABEL_PRINTER_RUN_SERVER)

View File

@ -89,7 +89,7 @@
{{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }} {{ FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name }}
</td> </td>
<td> <td>
<span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural) }}</span> <span class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount }}</span> <span id="product-{{ $currentStockEntry->product_id }}-qu-name">{{ $__n($currentStockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name_plural, true) }}</span>
<span class="small font-italic">@if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif</span> <span class="small font-italic">@if($currentStockEntry->amount_opened > 0){{ $__t('%s opened', $currentStockEntry->amount_opened) }}@endif</span>
</td> </td>
<td class=""></td> <td class=""></td>

View File

@ -717,7 +717,7 @@
@endif @endif
</td> </td>
<td class="font-italic"> <td class="font-italic">
{!! $__t('This means 1 %1$s is the same as %2$s %3$s', FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->from_qu_id)->name, '<span class="locale-number locale-number-quantity-amount">' . $quConversion->factor . '</span>', $__n($quConversion->factor, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name_plural)) !!} {!! $__t('This means 1 %1$s is the same as %2$s %3$s', FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->from_qu_id)->name, '<span class="locale-number locale-number-quantity-amount">' . $quConversion->factor . '</span>', $__n($quConversion->factor, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $quConversion->to_qu_id)->name_plural, true)) !!}
</td> </td>
</tr> </tr>
@endif @endif

View File

@ -197,7 +197,7 @@
@else @else
<span class="locale-number locale-number-quantity-amount">@if($recipePosition->amount == round($recipePosition->amount)){{ round($recipePosition->amount) }}@else{{ $recipePosition->amount }}@endif</span> <span class="locale-number locale-number-quantity-amount">@if($recipePosition->amount == round($recipePosition->amount)){{ round($recipePosition->amount) }}@else{{ $recipePosition->amount }}@endif</span>
@endif @endif
{{ $__n($recipePosition->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name_plural) }} {{ $__n($recipePosition->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name_plural, true) }}
@if(!empty($recipePosition->variable_amount)) @if(!empty($recipePosition->variable_amount))
<div class="small text-muted font-italic">{{ $__t('Variable amount') }}</div> <div class="small text-muted font-italic">{{ $__t('Variable amount') }}</div>

View File

@ -242,7 +242,7 @@
@endif @endif
<td data-order={{ <td data-order={{
$listItem->amount }}> $listItem->amount }}>
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural) }}@endif <span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}@endif
</td> </td>
<td> <td>
@if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else <span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span> @endif @if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else <span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span> @endif
@ -376,7 +376,7 @@
@if(!empty($listItem->product_id)) {{ $listItem->product_name }}<br>@endif<em>{!! nl2br($listItem->note) !!}</em> @if(!empty($listItem->product_id)) {{ $listItem->product_name }}<br>@endif<em>{!! nl2br($listItem->note) !!}</em>
</td> </td>
<td> <td>
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural) }}@endif <span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}@endif
</td> </td>
<td> <td>
@if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else <span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span> @endif @if(!empty($listItem->product_group_name)) {{ $listItem->product_group_name }} @else <span class="font-italic font-weight-light">{{ $__t('Ungrouped') }}</span> @endif
@ -400,7 +400,7 @@
<div class="w-75 print-layout-container print-layout-type-list d-none"> <div class="w-75 print-layout-container print-layout-type-list d-none">
@foreach($listItems as $listItem) @foreach($listItems as $listItem)
<div class="py-0"> <div class="py-0">
<span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural) }}@endif <span class="locale-number locale-number-quantity-amount">{{ $listItem->amount }}</span> @if(!empty($listItem->product_id)){{ $__n($listItem->amount, $listItem->qu_name, $listItem->qu_name_plural, true) }}@endif
@if(!empty($listItem->product_id)) {{ $listItem->product_name }}<br>@endif<em>{!! nl2br($listItem->note) !!}</em> @if(!empty($listItem->product_id)) {{ $listItem->product_name }}<br>@endif<em>{!! nl2br($listItem->note) !!}</em>
</div><br> </div><br>
@endforeach @endforeach

View File

@ -233,7 +233,7 @@
</td> </td>
<td data-order="{{ $stockEntry->amount }}"> <td data-order="{{ $stockEntry->amount }}">
<span id="stock-{{ $stockEntry->id }}-amount" <span id="stock-{{ $stockEntry->id }}-amount"
class="locale-number locale-number-quantity-amount">{{ $stockEntry->amount }}</span> <span id="product-{{ $stockEntry->product_id }}-qu-name">{{ $__n($stockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name_plural) }}</span> class="locale-number locale-number-quantity-amount">{{ $stockEntry->amount }}</span> <span id="product-{{ $stockEntry->product_id }}-qu-name">{{ $__n($stockEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockEntry->product_id)->qu_id_stock)->name_plural, true) }}</span>
<span id="stock-{{ $stockEntry->id }}-opened-amount" <span id="stock-{{ $stockEntry->id }}-opened-amount"
class="small font-italic">@if($stockEntry->open == 1){{ $__t('Opened') }}@endif</span> class="small font-italic">@if($stockEntry->open == 1){{ $__t('Opened') }}@endif</span>
</td> </td>

View File

@ -174,7 +174,7 @@
@endif @endif
</td> </td>
<td> <td>
<span class="locale-number locale-number-quantity-amount">{{ $stockLogEntry->amount }}</span> {{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural) }} <span class="locale-number locale-number-quantity-amount">{{ $stockLogEntry->amount }}</span> {{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural, true) }}
</td> </td>
<td> <td>
{{ $stockLogEntry->row_created_timestamp }} {{ $stockLogEntry->row_created_timestamp }}

View File

@ -120,7 +120,7 @@
{{ $journalEntry->user_display_name }} {{ $journalEntry->user_display_name }}
</td> </td>
<td> <td>
<span class="locale-number locale-number-quantity-amount">{{ $journalEntry->amount }}</span> {{ $__n($journalEntry->amount, $journalEntry->qu_name, $journalEntry->qu_name_plural) }} <span class="locale-number locale-number-quantity-amount">{{ $journalEntry->amount }}</span> {{ $__n($journalEntry->amount, $journalEntry->qu_name, $journalEntry->qu_name_plural, true) }}
</td> </td>
</tr> </tr>
@endforeach @endforeach

View File

@ -329,7 +329,7 @@
@if($currentStockEntry->is_aggregated_amount == 1) @if($currentStockEntry->is_aggregated_amount == 1)
<span class="pl-1 text-secondary"> <span class="pl-1 text-secondary">
<i class="fas fa-custom-sigma-sign"></i> <span id="product-{{ $currentStockEntry->product_id }}-amount-aggregated" <i class="fas fa-custom-sigma-sign"></i> <span id="product-{{ $currentStockEntry->product_id }}-amount-aggregated"
class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount_aggregated }}</span> {{ $__n($currentStockEntry->amount_aggregated, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural) }} class="locale-number locale-number-quantity-amount">{{ $currentStockEntry->amount_aggregated }}</span> {{ $__n($currentStockEntry->amount_aggregated, $currentStockEntry->qu_unit_name, $currentStockEntry->qu_unit_name_plural, true) }}
@if($currentStockEntry->amount_opened_aggregated > 0)<span id="product-{{ $currentStockEntry->product_id }}-opened-amount-aggregated" @if($currentStockEntry->amount_opened_aggregated > 0)<span id="product-{{ $currentStockEntry->product_id }}-opened-amount-aggregated"
class="small font-italic">{{ $__t('%s opened', $currentStockEntry->amount_opened_aggregated) }}</span>@endif class="small font-italic">{{ $__t('%s opened', $currentStockEntry->amount_opened_aggregated) }}</span>@endif
</span> </span>