|
32 | 32 | <img src="https://img.shields.io/github/issues/alexeev-prog/pyEchoNext?style=for-the-badge"> |
33 | 33 | <img src="https://img.shields.io/github/last-commit/alexeev-prog/pyEchoNext?style=for-the-badge"> |
34 | 34 | <img src="https://img.shields.io/pypi/wheel/uvolution?style=for-the-badge"> |
35 | | - <img src="https://img.shields.io/badge/coverage-54%25-54%25?style=for-the-badge" alt=""> |
| 35 | + <img src="https://img.shields.io/badge/coverage-73%25-73%25?style=for-the-badge" alt=""> |
36 | 36 | <img alt="PyPI - Downloads" src="https://img.shields.io/pypi/dm/pyEchoNext?style=for-the-badge"> |
37 | 37 | <img alt="PyPI - Version" src="https://img.shields.io/pypi/v/pyEchoNext?style=for-the-badge"> |
38 | 38 | <img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/pyEchoNext?style=for-the-badge"> |
@@ -60,7 +60,7 @@ Welcome to **EchoNext**, where innovation meets simplicity! Are you tired of the |
60 | 60 |
|
61 | 61 | **Imagine** a lightweight framework that empowers you to create modern web applications with lightning speed and flexibility. With EchoNext, you're not just coding; you're building a masterpiece! |
62 | 62 |
|
63 | | - > Last stable version: 0.7.14 alpha |
| 63 | + > Last stable version: 0.7.15 alpha |
64 | 64 |
|
65 | 65 | > Next Big Update: ASYNC & unicorn support |
66 | 66 |
|
@@ -105,7 +105,7 @@ Welcome to **EchoNext**, where innovation meets simplicity! Are you tired of the |
105 | 105 |
|
106 | 106 | ## ⚙️ Functionality |
107 | 107 |
|
108 | | - + i18n/l10n localization |
| 108 | + + i18n/l10n localization with [hermes-langlib](https://github.com/alexeev-prog/hermes_langlib). |
109 | 109 | + basic project documentation generator |
110 | 110 | + request/response |
111 | 111 | + middlewares (with basic session cookie middleware) |
@@ -173,6 +173,99 @@ calculate(4) # Output: 16 |
173 | 173 | ## 💻 Usage Examples |
174 | 174 | You can view examples at [examples directory](./examples). |
175 | 175 |
|
| 176 | +### i18n with hermes-langlib |
| 177 | +Hermes LangLib - a fast and light python library for translating, localizing and internationalizing your applications. The library is aimed at high speed and stability; it can be used in highly loaded projects. |
| 178 | + |
| 179 | +Directory tree: |
| 180 | + |
| 181 | +``` |
| 182 | +├── example.toml |
| 183 | +└── locales |
| 184 | + └── default.json |
| 185 | +``` |
| 186 | + |
| 187 | +Example config-file `example.toml`: |
| 188 | + |
| 189 | +```toml |
| 190 | +locale_directory="locales" |
| 191 | +default_locale_file="default.json" |
| 192 | +default_language="RU_RU" |
| 193 | +translator="google" |
| 194 | +``` |
| 195 | + |
| 196 | +Example locale file `locales/default.json`: |
| 197 | + |
| 198 | +```json |
| 199 | +{ |
| 200 | + "locales": { |
| 201 | + "RU": ["RU_RU"], |
| 202 | + "EN": ["EN_EN", "EN_US"] |
| 203 | + }, |
| 204 | + "RU": { |
| 205 | + "RU_RU": { |
| 206 | + "title": "Библиотека для интернационализации", |
| 207 | + "description": "Библиотека, которая позволит переводить ваши приложения", |
| 208 | + "mails_message": { |
| 209 | + "plural": "count", |
| 210 | + "^0$": "У вас нет ни одного письма", |
| 211 | + "11": "У вас есть {count} писем", |
| 212 | + "1$|1$": "У вас есть {count} письмо", |
| 213 | + "^(2|3|4)$|(2|3|4)$": "У вас есть {count} письма", |
| 214 | + "other": "У вас есть {count} писем" |
| 215 | + } |
| 216 | + } |
| 217 | + }, |
| 218 | + "EN": { |
| 219 | + "EN_EN": { |
| 220 | + "title": "Library for internationalization", |
| 221 | + "description": "A library that will allow you to translate your applications", |
| 222 | + "mails_message": { |
| 223 | + "plural": "count", |
| 224 | + "^0$": "You do not have any mail.", |
| 225 | + "^1$": "You have a new mail.", |
| 226 | + "other": "You have {count} new mails." |
| 227 | + } |
| 228 | + }, |
| 229 | + "EN_US": { |
| 230 | + "title": "Library for internationalization", |
| 231 | + "description": "A library that will allow you to translate your applications", |
| 232 | + "mails_message": { |
| 233 | + "plural": "count", |
| 234 | + "^0$": "You do not have any mail.", |
| 235 | + "^1$": "You have a new mail.", |
| 236 | + "other": "You have {count} new mails." |
| 237 | + } |
| 238 | + } |
| 239 | + } |
| 240 | +} |
| 241 | +``` |
| 242 | + |
| 243 | +Example usage: |
| 244 | + |
| 245 | +```python |
| 246 | +from hermes_langlib.locales import LocaleManager |
| 247 | +from hermes_langlib.storage import load_config |
| 248 | + |
| 249 | +config = load_config('example.toml') |
| 250 | + |
| 251 | +locale_manager = LocaleManager(config) |
| 252 | +print(locale_manager.get('title - {version}', 'default', 'RU_RU', version="0.1.0")) |
| 253 | +print(locale_manager.get('title - {version}', 'default', 'RU', version="0.1.0")) |
| 254 | +print(locale_manager.get('mails_message.', 'default', 'RU_RU', count=0)) |
| 255 | +print(locale_manager.get('mails_message', 'default', 'RU_RU', count=1)) |
| 256 | +print(locale_manager.get('mails_message', 'default', 'RU_RU', count=11)) |
| 257 | +print(locale_manager.get('mails_message', 'default', 'RU_RU', count=2)) |
| 258 | +print(locale_manager.get('mails_message', 'default', 'RU_RU', count=22)) |
| 259 | +print(locale_manager.get('mails_message', 'default', 'RU_RU', count=46)) |
| 260 | +print(locale_manager.get('mails_message', 'default', 'RU_RU', count=100000001)) |
| 261 | +print(locale_manager.translate("You have only three mails", "en", 'ru')) |
| 262 | +print(locale_manager.translate("У вас всего три письма", "ru", 'en')) |
| 263 | +``` |
| 264 | + |
| 265 | +You can read [Hermes-Langlib Specification at this link](https://github.com/alexeev-prog/hermes_langlib/tree/main?tab=readme-ov-file#-specifications). |
| 266 | + |
| 267 | +<p align="right">(<a href="#readme-top">back to top</a>)</p> |
| 268 | + |
176 | 269 | ### Basic With Depends Injection |
177 | 270 |
|
178 | 271 | ```python |
@@ -326,141 +419,6 @@ if __name__ == "__main__": |
326 | 419 | main() |
327 | 420 | ``` |
328 | 421 |
|
329 | | -### FullApp with locale, static files, docs generation |
330 | | -Also see in [examples](./examples/example_locale.py) |
331 | | - |
332 | | -```python |
333 | | -from pyechonext.apidoc_ui import APIDocUI, APIDocumentation |
334 | | -from pyechonext.app import ApplicationType, EchoNext |
335 | | -from pyechonext.config import SettingsConfigType, SettingsLoader |
336 | | -from pyechonext.middleware import middlewares |
337 | | -from pyechonext.mvc.controllers import PageController |
338 | | -from pyechonext.static import StaticFile |
339 | | -from pyechonext.template_engine.jinja import render_template |
340 | | -from pyechonext.urls import URL |
341 | | -from pyechonext.utils.exceptions import MethodNotAllow |
342 | | - |
343 | | - |
344 | | -class UsersView(PageController): |
345 | | - def get(self, request, response, *args, **kwargs): |
346 | | - return render_template( |
347 | | - request, |
348 | | - "index.html", |
349 | | - user_name="User", |
350 | | - session_id=request.session_id, |
351 | | - friends=["Bob", "Anna", "John"], |
352 | | - ) |
353 | | - |
354 | | - def post(self, request, response, *args, **kwargs): |
355 | | - raise MethodNotAllow(f"Request {request.path}: method not allow") |
356 | | - |
357 | | - |
358 | | -url_patterns = [URL(path="/users", controller=UsersView)] |
359 | | -config_loader = SettingsLoader(SettingsConfigType.PYMODULE, "el_config.py") |
360 | | -settings = config_loader.get_settings() |
361 | | -static_files = [StaticFile(settings, "styles.css")] |
362 | | -echonext = EchoNext( |
363 | | - __name__, |
364 | | - settings, |
365 | | - middlewares, |
366 | | - urls=url_patterns, |
367 | | - application_type=ApplicationType.HTML, |
368 | | - static_files=static_files, |
369 | | -) |
370 | | -apidoc = APIDocumentation(echonext) |
371 | | - |
372 | | - |
373 | | -@echonext.route_page("/api-docs") |
374 | | -def api_docs(request, response): |
375 | | - ui = APIDocUI(apidoc.generate_spec()) |
376 | | - return ui.generate_html_page() |
377 | | - |
378 | | - |
379 | | -@echonext.route_page("/book") |
380 | | -class BooksResource(PageController): |
381 | | - """ |
382 | | - This class describes a books resource. |
383 | | - """ |
384 | | - |
385 | | - def get(self, request, response, **kwargs): |
386 | | - """ |
387 | | - get queries |
388 | | -
|
389 | | - :param request: The request |
390 | | - :type request: Request |
391 | | - :param response: The response |
392 | | - :type response: Response |
393 | | - :param kwargs: The keywords arguments |
394 | | - :type kwargs: dictionary |
395 | | -
|
396 | | - :returns: result |
397 | | - :rtype: str |
398 | | - """ |
399 | | - return echonext.i18n_loader.get_string("title %{name}", name=str(request.GET)) |
400 | | - |
401 | | - def post(self, request, response, **kwargs): |
402 | | - """ |
403 | | - post queries |
404 | | -
|
405 | | - :param request: The request |
406 | | - :type request: Request |
407 | | - :param response: The response |
408 | | - :type response: Response |
409 | | - :param kwargs: The keywords arguments |
410 | | - :type kwargs: dictionary |
411 | | -
|
412 | | - :returns: result |
413 | | - :rtype: str |
414 | | - """ |
415 | | - return echonext.l10n_loader.format_currency(1305.50) |
416 | | - |
417 | | -``` |
418 | | - |
419 | | -Create file `static/styles.css`: |
420 | | - |
421 | | -```css |
422 | | -body { |
423 | | - color: #f8f2f2; |
424 | | - background: #1f1f1f; |
425 | | - font-family: monospace; |
426 | | -} |
427 | | -``` |
428 | | - |
429 | | -Create file `el_config.py`: |
430 | | - |
431 | | -```python |
432 | | -import os |
433 | | - |
434 | | -BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
435 | | -TEMPLATES_DIR = 'templates' |
436 | | -SECRET_KEY = 'secret-key' |
437 | | -LOCALE = 'RU_RU' |
438 | | -LOCALE_DIR = 'locales' |
439 | | -VERSION = "0.1.0" |
440 | | -DESCRIPTION = 'Example echonext webapp' |
441 | | -STATIC_DIR = 'static' |
442 | | -``` |
443 | | - |
444 | | -Create file `locales/RU_RU.json`: |
445 | | - |
446 | | -```python |
447 | | -{ |
448 | | - "i18n": { |
449 | | - "title": "pyEchoNext Веб-приложение с локалью", |
450 | | - "example one": "пример один" |
451 | | - }, |
452 | | - "l10n": { |
453 | | - "date_format": "%Y-%m-%d", |
454 | | - "time_format": "%H:%M", |
455 | | - "date_time_fromat": "%Y-%m-%d %H:%M", |
456 | | - "thousands_separator": ",", |
457 | | - "decimal_separator": ".", |
458 | | - "currency_symbol": "$", |
459 | | - "currency_format": "{symbol}{amount}" |
460 | | - } |
461 | | -} |
462 | | -``` |
463 | | - |
464 | 422 | <p align="right">(<a href="#readme-top">back to top</a>)</p> |
465 | 423 |
|
466 | 424 | ## 🔧 Specifications |
|
0 commit comments