mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-06-03 21:55:22 -04:00
* docs: fix typos * typos: fix typos found by `codespell` across the codebase * docs: fix `macOS` spelling * docs: fix `authentification` terminology "Authentification" is not a thing. * docs: fix `localhost` typo in example link * typos: fix in-code typos These are potentially higher risk, but no other mentions of these typos show up in the codebase.
185 lines
5.3 KiB
Python
185 lines
5.3 KiB
Python
import pathlib
|
||
|
||
import _static
|
||
import dotenv
|
||
import requests
|
||
from _gen_utils import log
|
||
from jinja2 import Template
|
||
from requests import Response
|
||
|
||
from mealie.schema._mealie import MealieModel
|
||
|
||
BASE = pathlib.Path(__file__).parent.parent.parent
|
||
|
||
API_KEY = dotenv.get_key(BASE / ".env", "CROWDIN_API_KEY")
|
||
|
||
if API_KEY is None or API_KEY == "":
|
||
log.info("CROWDIN_API_KEY is not set")
|
||
exit(1)
|
||
|
||
NAMES = {
|
||
"en-US": "American English",
|
||
"en-GB": "British English",
|
||
"af-ZA": "Afrikaans (Afrikaans)",
|
||
"ar-SA": "العربية (Arabic)",
|
||
"ca-ES": "Català (Catalan)",
|
||
"cs-CZ": "Čeština (Czech)",
|
||
"da-DK": "Dansk (Danish)",
|
||
"de-DE": "Deutsch (German)",
|
||
"el-GR": "Ελληνικά (Greek)",
|
||
"es-ES": "Español (Spanish)",
|
||
"fi-FI": "Suomi (Finnish)",
|
||
"fr-FR": "Français (French)",
|
||
"he-IL": "עברית (Hebrew)",
|
||
"hu-HU": "Magyar (Hungarian)",
|
||
"it-IT": "Italiano (Italian)",
|
||
"ja-JP": "日本語 (Japanese)",
|
||
"ko-KR": "한국어 (Korean)",
|
||
"no-NO": "Norsk (Norwegian)",
|
||
"nl-NL": "Nederlands (Dutch)",
|
||
"pl-PL": "Polski (Polish)",
|
||
"pt-BR": "Português do Brasil (Brazilian Portuguese)",
|
||
"pt-PT": "Português (Portuguese)",
|
||
"ro-RO": "Română (Romanian)",
|
||
"ru-RU": "Pусский (Russian)",
|
||
"sr-SP": "српски (Serbian)",
|
||
"sv-SE": "Svenska (Swedish)",
|
||
"tr-TR": "Türkçe (Turkish)",
|
||
"uk-UA": "Українська (Ukrainian)",
|
||
"vi-VN": "Tiếng Việt (Vietnamese)",
|
||
"zh-CN": "简体中文 (Chinese simplified)",
|
||
"zh-TW": "繁體中文 (Chinese traditional)",
|
||
}
|
||
|
||
LOCALE_TEMPLATE = """// This Code is auto generated by gen_global_components.py
|
||
export const LOCALES = [{% for locale in locales %}
|
||
{
|
||
name: "{{ locale.name }}",
|
||
value: "{{ locale.locale }}",
|
||
progress: {{ locale.progress }},
|
||
},{% endfor %}
|
||
]
|
||
|
||
"""
|
||
|
||
|
||
class TargetLanguage(MealieModel):
|
||
id: str
|
||
name: str
|
||
locale: str
|
||
threeLettersCode: str
|
||
twoLettersCode: str
|
||
progress: float = 0.0
|
||
|
||
|
||
class CrowdinApi:
|
||
project_name = "Mealie"
|
||
project_id = "451976"
|
||
api_key = API_KEY
|
||
|
||
def __init__(self, api_key: str):
|
||
api_key = api_key
|
||
|
||
@property
|
||
def headers(self) -> dict:
|
||
return {
|
||
"Content-Type": "application/json",
|
||
"Authorization": f"Bearer {self.api_key}",
|
||
}
|
||
|
||
def get_projects(self) -> Response:
|
||
return requests.get("https://api.crowdin.com/api/v2/projects", headers=self.headers)
|
||
|
||
def get_project(self) -> Response:
|
||
return requests.get(f"https://api.crowdin.com/api/v2/projects/{self.project_id}", headers=self.headers)
|
||
|
||
def get_languages(self) -> list[TargetLanguage]:
|
||
response = self.get_project()
|
||
tls = response.json()["data"]["targetLanguages"]
|
||
|
||
models = [TargetLanguage(**t) for t in tls]
|
||
|
||
models.insert(
|
||
0,
|
||
TargetLanguage(
|
||
id="en-US", name="English", locale="en-US", threeLettersCode="en", twoLettersCode="en", progress=100
|
||
),
|
||
)
|
||
|
||
progress: list[dict] = self.get_progress()["data"]
|
||
|
||
for model in models:
|
||
if model.locale in NAMES:
|
||
model.name = NAMES[model.locale]
|
||
|
||
for p in progress:
|
||
if p["data"]["languageId"] == model.id:
|
||
model.progress = p["data"]["translationProgress"]
|
||
|
||
models.sort(key=lambda x: x.locale, reverse=True)
|
||
return models
|
||
|
||
def get_progress(self) -> dict:
|
||
response = requests.get(
|
||
f"https://api.crowdin.com/api/v2/projects/{self.project_id}/languages/progress?limit=500",
|
||
headers=self.headers,
|
||
)
|
||
return response.json()
|
||
|
||
|
||
from pathlib import Path
|
||
|
||
from _gen_utils import inject_inline
|
||
from _static import CodeKeys
|
||
|
||
PROJECT_DIR = Path(__file__).parent.parent.parent
|
||
|
||
|
||
datetime_dir = PROJECT_DIR / "frontend" / "lang" / "dateTimeFormats"
|
||
locales_dir = PROJECT_DIR / "frontend" / "lang" / "messages"
|
||
nuxt_config = PROJECT_DIR / "frontend" / "nuxt.config.js"
|
||
|
||
"""
|
||
This snippet walks the message and dat locales directories and generates the import information
|
||
for the nuxt.config.js file and automatically injects it into the nuxt.config.js file. Note that
|
||
the code generation ID is hardcoded into the script and required in the nuxt config.
|
||
"""
|
||
|
||
|
||
def inject_nuxt_values():
|
||
all_date_locales = [
|
||
f'"{match.stem}": require("./lang/dateTimeFormats/{match.name}"),' for match in datetime_dir.glob("*.json")
|
||
]
|
||
|
||
all_langs = []
|
||
for match in locales_dir.glob("*.json"):
|
||
lang_string = f'{{ code: "{match.stem}", file: "{match.name}" }},'
|
||
all_langs.append(lang_string)
|
||
|
||
log.info(f"injecting locales into nuxt config -> {nuxt_config}")
|
||
inject_inline(nuxt_config, CodeKeys.nuxt_local_messages, all_langs)
|
||
inject_inline(nuxt_config, CodeKeys.nuxt_local_dates, all_date_locales)
|
||
|
||
|
||
def generate_locales_ts_file():
|
||
api = CrowdinApi("")
|
||
models = api.get_languages()
|
||
tmpl = Template(LOCALE_TEMPLATE)
|
||
rendered = tmpl.render(locales=models)
|
||
|
||
log.info(f"generating locales ts file -> {_static.CodeDest.use_locales}")
|
||
with open(_static.CodeDest.use_locales, "w") as f:
|
||
f.write(rendered) # type:ignore
|
||
|
||
|
||
def main():
|
||
generate_locales_ts_file()
|
||
|
||
inject_nuxt_values()
|
||
|
||
log.info("finished code generation")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|