diff --git a/dev/code-generation/gen_ts_locales.py b/dev/code-generation/gen_ts_locales.py index f26a3e16c8f0..72bde6481168 100644 --- a/dev/code-generation/gen_ts_locales.py +++ b/dev/code-generation/gen_ts_locales.py @@ -35,18 +35,24 @@ LOCALE_DATA: dict[str, LocaleData] = { "es-ES": LocaleData(name="Español (Spanish)"), "fi-FI": LocaleData(name="Suomi (Finnish)"), "fr-FR": LocaleData(name="Français (French)"), + "gl-ES": LocaleData(name="Galego (Galician)"), "he-IL": LocaleData(name="עברית (Hebrew)", dir="rtl"), + "hr-HR": LocaleData(name="Hrvatski (Croatian)"), "hu-HU": LocaleData(name="Magyar (Hungarian)"), + "is-IS": LocaleData(name="Íslenska (Icelandic)"), "it-IT": LocaleData(name="Italiano (Italian)"), "ja-JP": LocaleData(name="日本語 (Japanese)"), "ko-KR": LocaleData(name="한국어 (Korean)"), - "no-NO": LocaleData(name="Norsk (Norwegian)"), + "lt-LT": LocaleData(name="Lietuvių (Lithuanian)"), + "lv-LV": LocaleData(name="Latviešu (Latvian)"), "nl-NL": LocaleData(name="Nederlands (Dutch)"), + "no-NO": LocaleData(name="Norsk (Norwegian)"), "pl-PL": LocaleData(name="Polski (Polish)"), "pt-BR": LocaleData(name="Português do Brasil (Brazilian Portuguese)"), "pt-PT": LocaleData(name="Português (Portuguese)"), "ro-RO": LocaleData(name="Română (Romanian)"), "ru-RU": LocaleData(name="Pусский (Russian)"), + "sl-SI": LocaleData(name="Slovenščina (Slovenian)"), "sr-SP": LocaleData(name="српски (Serbian)"), "sv-SE": LocaleData(name="Svenska (Swedish)"), "tr-TR": LocaleData(name="Türkçe (Turkish)"), diff --git a/frontend/lang/dateTimeFormats/gl-ES.json b/frontend/lang/dateTimeFormats/gl-ES.json new file mode 100644 index 000000000000..47f1f0c52e7b --- /dev/null +++ b/frontend/lang/dateTimeFormats/gl-ES.json @@ -0,0 +1,21 @@ +{ + "short": { + "month": "short", + "day": "numeric", + "weekday": "long" + }, + "medium": { + "month": "long", + "day": "numeric", + "weekday": "long", + "year": "numeric" + }, + "long": { + "year": "numeric", + "month": "long", + "day": "numeric", + "weekday": "long", + "hour": "numeric", + "minute": "numeric" + } +} diff --git a/frontend/lang/dateTimeFormats/hr-HR.json b/frontend/lang/dateTimeFormats/hr-HR.json new file mode 100644 index 000000000000..47f1f0c52e7b --- /dev/null +++ b/frontend/lang/dateTimeFormats/hr-HR.json @@ -0,0 +1,21 @@ +{ + "short": { + "month": "short", + "day": "numeric", + "weekday": "long" + }, + "medium": { + "month": "long", + "day": "numeric", + "weekday": "long", + "year": "numeric" + }, + "long": { + "year": "numeric", + "month": "long", + "day": "numeric", + "weekday": "long", + "hour": "numeric", + "minute": "numeric" + } +} diff --git a/frontend/lang/dateTimeFormats/is-IS.json b/frontend/lang/dateTimeFormats/is-IS.json new file mode 100644 index 000000000000..47f1f0c52e7b --- /dev/null +++ b/frontend/lang/dateTimeFormats/is-IS.json @@ -0,0 +1,21 @@ +{ + "short": { + "month": "short", + "day": "numeric", + "weekday": "long" + }, + "medium": { + "month": "long", + "day": "numeric", + "weekday": "long", + "year": "numeric" + }, + "long": { + "year": "numeric", + "month": "long", + "day": "numeric", + "weekday": "long", + "hour": "numeric", + "minute": "numeric" + } +} diff --git a/frontend/lang/dateTimeFormats/lt-LT.json b/frontend/lang/dateTimeFormats/lt-LT.json new file mode 100644 index 000000000000..47f1f0c52e7b --- /dev/null +++ b/frontend/lang/dateTimeFormats/lt-LT.json @@ -0,0 +1,21 @@ +{ + "short": { + "month": "short", + "day": "numeric", + "weekday": "long" + }, + "medium": { + "month": "long", + "day": "numeric", + "weekday": "long", + "year": "numeric" + }, + "long": { + "year": "numeric", + "month": "long", + "day": "numeric", + "weekday": "long", + "hour": "numeric", + "minute": "numeric" + } +} diff --git a/frontend/lang/dateTimeFormats/lv-LV.json b/frontend/lang/dateTimeFormats/lv-LV.json new file mode 100644 index 000000000000..47f1f0c52e7b --- /dev/null +++ b/frontend/lang/dateTimeFormats/lv-LV.json @@ -0,0 +1,21 @@ +{ + "short": { + "month": "short", + "day": "numeric", + "weekday": "long" + }, + "medium": { + "month": "long", + "day": "numeric", + "weekday": "long", + "year": "numeric" + }, + "long": { + "year": "numeric", + "month": "long", + "day": "numeric", + "weekday": "long", + "hour": "numeric", + "minute": "numeric" + } +} diff --git a/frontend/lang/dateTimeFormats/sl-SI.json b/frontend/lang/dateTimeFormats/sl-SI.json new file mode 100644 index 000000000000..47f1f0c52e7b --- /dev/null +++ b/frontend/lang/dateTimeFormats/sl-SI.json @@ -0,0 +1,21 @@ +{ + "short": { + "month": "short", + "day": "numeric", + "weekday": "long" + }, + "medium": { + "month": "long", + "day": "numeric", + "weekday": "long", + "year": "numeric" + }, + "long": { + "year": "numeric", + "month": "long", + "day": "numeric", + "weekday": "long", + "hour": "numeric", + "minute": "numeric" + } +} diff --git a/frontend/nuxt.config.js b/frontend/nuxt.config.js index 851f2fc567c0..b27bed70b9c8 100644 --- a/frontend/nuxt.config.js +++ b/frontend/nuxt.config.js @@ -260,6 +260,12 @@ export default { "en-GB": require("./lang/dateTimeFormats/en-GB.json"), "fi-FI": require("./lang/dateTimeFormats/fi-FI.json"), "vi-VN": require("./lang/dateTimeFormats/vi-VN.json"), + "sl-SI": require("./lang/dateTimeFormats/sl-SI.json"), + "lv-LV": require("./lang/dateTimeFormats/lv-LV.json"), + "is-IS": require("./lang/dateTimeFormats/is-IS.json"), + "gl-ES": require("./lang/dateTimeFormats/gl-ES.json"), + "lt-LT": require("./lang/dateTimeFormats/lt-LT.json"), + "hr-HR": require("./lang/dateTimeFormats/hr-HR.json"), // END: DATE_LOCALES }, fallbackLocale: "en-US", diff --git a/mealie/lang/messages/en-US.json b/mealie/lang/messages/en-US.json index 16bee3cc7743..3d641cf66835 100644 --- a/mealie/lang/messages/en-US.json +++ b/mealie/lang/messages/en-US.json @@ -3,7 +3,11 @@ "server-error": "An unexpected error occurred" }, "recipe": { - "unique-name-error": "Recipe names must be unique" + "unique-name-error": "Recipe names must be unique", + "recipe-defaults": { + "ingredient-note": "1 Cup Flour", + "step-text": "Recipe steps as well as other fields in the recipe page support markdown syntax.\n\n**Add a link**\n\n[My Link](https://demo.mealie.io)\n" + } }, "mealplan": { "no-recipes-match-your-rules": "No recipes match your rules" diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py index a10131a415d0..a6b87fef0aa4 100644 --- a/mealie/routes/recipe/recipe_crud_routes.py +++ b/mealie/routes/recipe/recipe_crud_routes.py @@ -72,7 +72,7 @@ class BaseRecipeController(BaseCrudController): @cached_property def service(self) -> RecipeService: - return RecipeService(self.repos, self.user, self.group) + return RecipeService(self.repos, self.user, self.group, translator=self.translator) @cached_property def mixins(self): diff --git a/mealie/services/migrations/_migration_base.py b/mealie/services/migrations/_migration_base.py index bbb8d5486255..c8899dce5b8a 100644 --- a/mealie/services/migrations/_migration_base.py +++ b/mealie/services/migrations/_migration_base.py @@ -70,7 +70,7 @@ class BaseMigrator(BaseService): self.logger = root_logger.get_logger() self.helpers = DatabaseMigrationHelpers(self.db, self.session, self.group.id, self.user.id) - self.recipe_service = RecipeService(db, user, group) + self.recipe_service = RecipeService(db, user, group, translator=self.translator) super().__init__() diff --git a/mealie/services/recipe/recipe_service.py b/mealie/services/recipe/recipe_service.py index 7fde8a2b1704..18f2ff407296 100644 --- a/mealie/services/recipe/recipe_service.py +++ b/mealie/services/recipe/recipe_service.py @@ -11,6 +11,7 @@ from fastapi import UploadFile from slugify import slugify from mealie.core import exceptions +from mealie.lang.providers import Translator from mealie.pkgs import cache from mealie.repos.repository_factory import AllRepositories from mealie.repos.repository_generic import RepositoryGeneric @@ -26,22 +27,16 @@ from mealie.services.recipe.recipe_data_service import RecipeDataService from .template_service import TemplateService -step_text = """Recipe steps as well as other fields in the recipe page support markdown syntax. - -**Add a link** - -[My Link](https://demo.mealie.io) - -""" - -ingredient_note = "1 Cup Flour" - class RecipeService(BaseService): - def __init__(self, repos: AllRepositories, user: PrivateUser, group: GroupInDB): + def __init__(self, repos: AllRepositories, user: PrivateUser, group: GroupInDB, translator: Translator): self.repos = repos self.user = user self.group = group + + self.translator = translator + self.t = translator.t + super().__init__() def _get_recipe(self, data: str | UUID, key: str | None = None) -> Recipe: @@ -85,8 +80,7 @@ class RecipeService(BaseService): rmtree(recipe_dir, ignore_errors=True) self.logger.info(f"Recipe Directory Removed: {recipe.slug}") - @staticmethod - def _recipe_creation_factory(user: PrivateUser, name: str, additional_attrs: dict | None = None) -> Recipe: + def _recipe_creation_factory(self, name: str, additional_attrs: dict | None = None) -> Recipe: """ The main creation point for recipes. The factor method returns an instance of the Recipe Schema class with the appropriate defaults set. Recipes should not be created @@ -94,18 +88,20 @@ class RecipeService(BaseService): """ additional_attrs = additional_attrs or {} additional_attrs["name"] = name - additional_attrs["user_id"] = user.id - additional_attrs["group_id"] = user.group_id + additional_attrs["user_id"] = self.user.id + additional_attrs["group_id"] = self.user.group_id if additional_attrs.get("tags"): for i in range(len(additional_attrs.get("tags", []))): - additional_attrs["tags"][i]["group_id"] = user.group_id + additional_attrs["tags"][i]["group_id"] = self.user.group_id if not additional_attrs.get("recipe_ingredient"): - additional_attrs["recipe_ingredient"] = [RecipeIngredient(note=ingredient_note)] + additional_attrs["recipe_ingredient"] = [ + RecipeIngredient(note=self.t("recipe.recipe-defaults.ingredient-note")) + ] if not additional_attrs.get("recipe_instructions"): - additional_attrs["recipe_instructions"] = [RecipeStep(text=step_text)] + additional_attrs["recipe_instructions"] = [RecipeStep(text=self.t("recipe.recipe-defaults.step-text"))] return Recipe(**additional_attrs) @@ -126,11 +122,7 @@ class RecipeService(BaseService): if create_data.name is None: create_data.name = "New Recipe" - data: Recipe = self._recipe_creation_factory( - self.user, - name=create_data.name, - additional_attrs=create_data.model_dump(), - ) + data: Recipe = self._recipe_creation_factory(name=create_data.name, additional_attrs=create_data.model_dump()) if isinstance(create_data, CreateRecipe) or create_data.settings is None: if self.group.preferences is not None: @@ -294,11 +286,7 @@ class RecipeService(BaseService): else list(map(copy_recipe_ingredient, old_recipe.recipe_ingredient)) ) - new_recipe = self._recipe_creation_factory( - self.user, - new_name, - additional_attrs=new_recipe.model_dump(), - ) + new_recipe = self._recipe_creation_factory(new_name, additional_attrs=new_recipe.model_dump()) new_recipe = self.repos.recipes.create(new_recipe)