{"id":29051460,"url":"https://github.com/giacomomarchioro/prejinja","last_synced_at":"2026-05-08T04:31:38.342Z","repository":{"id":210073417,"uuid":"702537670","full_name":"giacomomarchioro/prejinja","owner":"giacomomarchioro","description":"A Jinja2 alternative to Babel and a Jinja2 pre-processor.","archived":false,"fork":false,"pushed_at":"2024-03-18T07:51:54.000Z","size":43,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-03-18T08:47:36.331Z","etag":null,"topics":["django","flask","jinja2","multilingual-websites","preprocessor"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/giacomomarchioro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2023-10-09T14:02:05.000Z","updated_at":"2023-12-20T07:54:40.000Z","dependencies_parsed_at":"2023-12-18T16:30:39.034Z","dependency_job_id":"1b6b409d-c1e6-4e00-a2e8-cbeb77ead137","html_url":"https://github.com/giacomomarchioro/prejinja","commit_stats":null,"previous_names":["giacomomarchioro/prejinja"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/giacomomarchioro/prejinja","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fprejinja","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fprejinja/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fprejinja/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fprejinja/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/giacomomarchioro","download_url":"https://codeload.github.com/giacomomarchioro/prejinja/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giacomomarchioro%2Fprejinja/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262150132,"owners_count":23266835,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","flask","jinja2","multilingual-websites","preprocessor"],"created_at":"2025-06-26T22:10:36.811Z","updated_at":"2026-05-08T04:31:33.322Z","avatar_url":"https://github.com/giacomomarchioro.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# prejinja\nA Jinja2 alternative to Babel and a Jinja2 preprocessor.\n\nPrejinja is a Jinja2 preprocessor that extracts static variables to a JSON file that is used for translating the website into different languages.\n\n## Installation\n\n```\npip install git+https://github.com/giacomomarchioro/prejinja\n```\n\n## How it works?\nPrejinja preprocess special jinja2 templates for each language and allows you to use standard jinja2 to be processes \"on the fly\".\nA working example is shown in the example folder of this repository.\n1. `srctempaltes` folder contains the jinja2 source templates. However, all the translatable text is assigned to variables.\n2. For each text the user create a variable between `[=` and `=]` tags (e.g. `[= p_website_description_50c =]` ).\n3. You can add some logic to be pre-processed using `[.` and  `.]` tags.\n4. Standard Jinja2 logic can be added and will not conflict with prejinja, however might be wise to pre-process much of the template.\n5. Using `prejinjaget` command the variables will be mapped into a `translations.po.json` file.\n6. Once the content has been written and translated in the `translations.po.json`, `prejinjaput` command preprocess the templates and save the results in the `templates` dir. (you can also use `prejinjaput --lipsum` to see a preview with loreipsum text.)\n\nPrejinja will create a file for each language and use a prefix to identify the file (e.g. `en-index.html`, `de-index.html`).\nAt this point you can return the correct language translation based on the current locale.\n\n## On the templates\nThere are some built-in variables in the pre-jinja2 context:\n`_LANG` : the current language tag of the page e.g. `en`.\n`_OTHERLANGUAGES` : a list of other language supported by the website (e.g. `[\"es\",\"de\"]`).\n`_LANGUAGESNAMES` : dictionary containing the language name `_LANGUAGESNAMES[\"en\"] = \"english\"`.\n`_LANGUAGESFLAGS` : a dictionary containing the flag emoticon `_LANGUAGESFLAGS[\"en\"] = \"🇬🇧\"`.\n\nA `source template` might look something like this:\n\n```\n[. extends './srctemplates/includes/layout.html' .]\n[. block  head .]\n[. endblock  head .]\n[. block  body .]\n\u003ch1\u003e [= h1_Second_Page_8c =] \u003c/h1\u003e\n\u003cp\u003e [= p_secondpage_description_50c =] \u003c/p\u003e\n\u003ch1\u003e [= h1_How_it_works_20c =] \u003c/h1\u003e\n\u003cp\u003e [= p_prejinja_compile_60c =] \u003c/p\u003e\n\u003ch1\u003e [= h1_a_test_with_format =]\u003c/h1\u003e\n\u003cp\u003e {{\"[= format_test =]\"|format(3)}} \u003c/p\u003e\n[. endblock  body .]\n```\n\n## A typical Flask application\nA Flask application could look like this:\n\n```python\nfrom flask import Flask, render_template, request, redirect, url_for,abort\n\napp = Flask(__name__)\nsupported_languages = [\"en\", \"es\", \"it\"]\n\n@app.route('/')\ndef localeRedirect():\n   lang = request.accept_languages.best_match(supported_languages)\n   return redirect(url_for('indexPage', lang=lang))\n\n# OPTION 1: single endpoint for multiple languages\n@app.route('/\u003clang\u003e/test')\ndef indexPage(lang):\n   if lang not in supported_languages:abort(404)\n   # use {{ url_for('indexPage', lang='[= _LANG =]' }} in the source template\n   return render_template(f\"{lang}-index.html\")\n\n# OPTION 2: multiple endpoints can be used for translating also the URLs\n@app.route('/en/apple',endpoint=\"en_secondPage\")\n@app.route('/es/manzana',endpoint=\"es_secondPage\")\n@app.route('/it/mela',endpoint=\"it_secondPage\")\n#@app.route('/xx/lorem',endpoint=\"xx_secondPage\") # LoreIpsum\ndef secondPage():\n    # use {{ url_for('[= _LANG =]_secondPage'}} in the source template\n    # OR translate the URLs directly [= URL_mela =] and don't use `url_for`\n    lang = request.path.split(\"/\")[1]\n    return render_template(f\"{lang}-endpointstest.html\")\n\nif __name__  == '__main__':\n\tapp.run(debug=True)\n```\n\n### Single endpoint\nThe easiest option is to not translating the URLs (e.g. `en/index` translated to `it/index`) like in OPTION 1 of the example. However, it is a good practice to translate also the URLs to add meaning to the URL itself also when translated.\n\n### Multiple endpoints\nIf you want also the URLs to be translated (e.g. `en/index` translated to `it/indice`) you have to define multiple endpoints as shown in OPTION 2 of the example (see examples folders for a working example).\nThe process will be a little more complicated.\n\nHere we provide the components for the two cases:\n\n### Herflang\n\n#### Single endpoint\n\n```html\n[. for _otherlang in _OTHERLANGUAGES .]\n\u003clink rel=\"alternate\" hreflang=\"[= _otherlang =]\" href=\"{{ url_for(request.endpoint, lang='[= _otherlang =]', _external=true) }}\" /\u003e\n[. endfor .]\n```\n#### Multiple endpoints\n\n```html\n\u003chtml lang=\"[= _LANG =]\" xml:lang=\"[= _LANG =]\" xmlns=\"http://www.w3.org/1999/xhtml\"\u003e\n[. for _otherlang in _OTHERLANGUAGES .]\n\u003clink rel=\"alternate\" hreflang=\"[= _otherlang =]\" href=\"{{ url_for(request.endpoint.replace('[= _LANG =]','[= _otherlang =]',1))}}\" /\u003e\n[. endfor .]\n```\n\n### Language picker\n\n#### Single endpoint\n```html\n  \u003cdiv class=\"dropdown\"\u003e\n    \u003cbutton class=\"dropbtn\"\u003e[= _LANGUAGESFLAGS[_LANG] =]\n      \u003ci class=\"fa fa-caret-down\"\u003e\u003c/i\u003e\n    \u003c/button\u003e\n    \u003cdiv class=\"dropdown-content\"\u003e\n      [. for _otherlang in _OTHERLANGUAGES .]\n      \u003ca class=\"dropdown-item\" onclick=\"location.replace(window.location.href.replace('[= _LANG =]', '[= _otherlang =]'))\"\u003e[= _LANGUAGESFLAGS[_otherlang] =][= _LANGUAGESNAMES[_otherlang] =]\u003c/a\u003e\n      [. endfor .]\n    \u003c/div\u003e\n  \u003c/div\u003e\n```\n\n#### Multiple endpoints\n```html\n  \u003cdiv class=\"dropdown\"\u003e\n    \u003cbutton class=\"dropbtn\"\u003e[= _LANGUAGESFLAGS[_LANG] =]\n      \u003ci class=\"fa fa-caret-down\"\u003e\u003c/i\u003e\n    \u003c/button\u003e\n    \u003cdiv class=\"dropdown-content\"\u003e\n      [. for _otherlang in _OTHERLANGUAGES .]\n      \u003ca class=\"dropdown-item\" href={{ url_for(request.endpoint.replace(\"[= _LANG =]\",\"[= _otherlang =]\",1))}}\u003e[= _LANGUAGESFLAGS[_otherlang] =][= _LANGUAGESNAMES[_otherlang] =]\u003c/a\u003e\n      [. endfor .]\n    \u003c/div\u003e\n  \u003c/div\u003e\n```\n\n \u003e Pay attention that formatter might split this line in pieces! Better to create a separate file and use include!\n\n## Plurals\nPlurals are handled by Jinja:\n\n```\n{% if number == 1 %}\n  [= p_one_user_logged_in_10c =]\n{% elif number \u003e 1 %}\n  \"[= p_n_users_logged_ind_10c =]\"|format(number)\n{% else %}\n  [= p_no_user_logged_in_10c =]\n{% endif %}\n```\n\n## The benefits\nThe goal to this package is to separate the layout from the content. In this way it is possible for the WEB developer to create a draft of the layout based on the user needs and leave the copywriter and the translators to work on a separate `.json` file.\n\n## For debuggin\n```\nimport prejinja.CLIpreprocessor as CI\nCI.preJinjaPut()\n```\n\n\n## Similar packages\n[Flask-Babel](https://python-babel.github.io/flask-babel/#)\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiacomomarchioro%2Fprejinja","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgiacomomarchioro%2Fprejinja","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiacomomarchioro%2Fprejinja/lists"}