ErisPulse 2.6.3.dev0__tar.gz → 2.7.0.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/PKG-INFO +1 -1
  2. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/pyproject.toml +1 -1
  3. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/create.py +43 -3
  4. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/__init__.py +20 -0
  5. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/adapter.py +77 -5
  6. {erispulse-2.6.3.dev0/src/ErisPulse/runtime → erispulse-2.7.0.dev0/src/ErisPulse/Core/Bases}/config_schema.py +62 -16
  7. erispulse-2.7.0.dev0/src/ErisPulse/Core/Bases/i18n_schema.py +239 -0
  8. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/module.py +37 -3
  9. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/adapter.py +14 -1
  10. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/constants.py +14 -0
  11. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/module.py +11 -0
  12. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/__init__.py +32 -14
  13. erispulse-2.7.0.dev0/src/ErisPulse/runtime/config_schema.py +37 -0
  14. erispulse-2.6.3.dev0/src/ErisPulse/CLI/__init__.pyi +0 -16
  15. erispulse-2.6.3.dev0/src/ErisPulse/CLI/base.pyi +0 -52
  16. erispulse-2.6.3.dev0/src/ErisPulse/CLI/cli.pyi +0 -89
  17. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/__init__.pyi +0 -9
  18. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/create.pyi +0 -95
  19. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/init.pyi +0 -94
  20. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/install.pyi +0 -78
  21. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/language.pyi +0 -51
  22. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/list.pyi +0 -58
  23. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/list_remote.pyi +0 -44
  24. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/run.pyi +0 -108
  25. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/self_update.pyi +0 -68
  26. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/types.pyi +0 -148
  27. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/uninstall.pyi +0 -37
  28. erispulse-2.6.3.dev0/src/ErisPulse/CLI/commands/upgrade.pyi +0 -31
  29. erispulse-2.6.3.dev0/src/ErisPulse/CLI/console.pyi +0 -51
  30. erispulse-2.6.3.dev0/src/ErisPulse/CLI/hints.pyi +0 -71
  31. erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/__init__.pyi +0 -115
  32. erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/__init__.pyi +0 -12
  33. erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/en.pyi +0 -8
  34. erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/ja.pyi +0 -8
  35. erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/ru.pyi +0 -8
  36. erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/zh_cn.pyi +0 -8
  37. erispulse-2.6.3.dev0/src/ErisPulse/CLI/i18n/locales/zh_tw.pyi +0 -8
  38. erispulse-2.6.3.dev0/src/ErisPulse/CLI/registry.pyi +0 -92
  39. erispulse-2.6.3.dev0/src/ErisPulse/CLI/utils/__init__.pyi +0 -11
  40. erispulse-2.6.3.dev0/src/ErisPulse/CLI/utils/display.pyi +0 -114
  41. erispulse-2.6.3.dev0/src/ErisPulse/CLI/utils/file_watcher.pyi +0 -123
  42. erispulse-2.6.3.dev0/src/ErisPulse/CLI/utils/package_manager.pyi +0 -391
  43. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/__init__.pyi +0 -19
  44. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/adapter.pyi +0 -786
  45. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/client.pyi +0 -277
  46. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/errors.pyi +0 -115
  47. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/kv_builder.pyi +0 -125
  48. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/manager.pyi +0 -138
  49. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/module.pyi +0 -137
  50. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/router.pyi +0 -451
  51. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/send_builder.pyi +0 -231
  52. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/send_rules.pyi +0 -167
  53. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/storage.pyi +0 -397
  54. erispulse-2.6.3.dev0/src/ErisPulse/Core/Bases/websocket.pyi +0 -194
  55. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/__init__.pyi +0 -28
  56. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/base.pyi +0 -71
  57. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/command.pyi +0 -121
  58. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/message.pyi +0 -102
  59. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/message_builder.pyi +0 -147
  60. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/meta.pyi +0 -101
  61. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/notice.pyi +0 -117
  62. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/request.pyi +0 -86
  63. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/session_type.pyi +0 -216
  64. erispulse-2.6.3.dev0/src/ErisPulse/Core/Event/wrapper.pyi +0 -1170
  65. erispulse-2.6.3.dev0/src/ErisPulse/Core/__init__.pyi +0 -36
  66. erispulse-2.6.3.dev0/src/ErisPulse/Core/adapter.pyi +0 -494
  67. erispulse-2.6.3.dev0/src/ErisPulse/Core/assets/__init__.pyi +0 -65
  68. erispulse-2.6.3.dev0/src/ErisPulse/Core/client.pyi +0 -407
  69. erispulse-2.6.3.dev0/src/ErisPulse/Core/config.pyi +0 -129
  70. erispulse-2.6.3.dev0/src/ErisPulse/Core/constants.pyi +0 -217
  71. erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/__init__.pyi +0 -153
  72. erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/constants.pyi +0 -8
  73. erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/__init__.pyi +0 -12
  74. erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/en.pyi +0 -8
  75. erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/ja.pyi +0 -8
  76. erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/ru.pyi +0 -8
  77. erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/zh_cn.pyi +0 -8
  78. erispulse-2.6.3.dev0/src/ErisPulse/Core/i18n/locales/zh_tw.pyi +0 -8
  79. erispulse-2.6.3.dev0/src/ErisPulse/Core/lifecycle.pyi +0 -240
  80. erispulse-2.6.3.dev0/src/ErisPulse/Core/logger.pyi +0 -378
  81. erispulse-2.6.3.dev0/src/ErisPulse/Core/master.pyi +0 -119
  82. erispulse-2.6.3.dev0/src/ErisPulse/Core/module.pyi +0 -300
  83. erispulse-2.6.3.dev0/src/ErisPulse/Core/router.pyi +0 -651
  84. erispulse-2.6.3.dev0/src/ErisPulse/Core/storage.pyi +0 -455
  85. erispulse-2.6.3.dev0/src/ErisPulse/__init__.pyi +0 -20
  86. erispulse-2.6.3.dev0/src/ErisPulse/__main__.pyi +0 -21
  87. erispulse-2.6.3.dev0/src/ErisPulse/finders/__init__.pyi +0 -19
  88. erispulse-2.6.3.dev0/src/ErisPulse/finders/adapter.pyi +0 -91
  89. erispulse-2.6.3.dev0/src/ErisPulse/finders/bases/__init__.pyi +0 -4
  90. erispulse-2.6.3.dev0/src/ErisPulse/finders/bases/finder.pyi +0 -66
  91. erispulse-2.6.3.dev0/src/ErisPulse/finders/module.pyi +0 -91
  92. erispulse-2.6.3.dev0/src/ErisPulse/loaders/__init__.pyi +0 -18
  93. erispulse-2.6.3.dev0/src/ErisPulse/loaders/adapter.pyi +0 -96
  94. erispulse-2.6.3.dev0/src/ErisPulse/loaders/bases/__init__.pyi +0 -4
  95. erispulse-2.6.3.dev0/src/ErisPulse/loaders/bases/loader.pyi +0 -20
  96. erispulse-2.6.3.dev0/src/ErisPulse/loaders/module.pyi +0 -185
  97. erispulse-2.6.3.dev0/src/ErisPulse/loaders/strategy.pyi +0 -90
  98. erispulse-2.6.3.dev0/src/ErisPulse/loaders/strict.pyi +0 -118
  99. erispulse-2.6.3.dev0/src/ErisPulse/runtime/__init__.pyi +0 -18
  100. erispulse-2.6.3.dev0/src/ErisPulse/runtime/config_schema.pyi +0 -285
  101. erispulse-2.6.3.dev0/src/ErisPulse/runtime/context.pyi +0 -34
  102. erispulse-2.6.3.dev0/src/ErisPulse/runtime/exceptions.pyi +0 -95
  103. erispulse-2.6.3.dev0/src/ErisPulse/runtime/frame_config.pyi +0 -116
  104. erispulse-2.6.3.dev0/src/ErisPulse/runtime/hints.pyi +0 -266
  105. erispulse-2.6.3.dev0/src/ErisPulse/runtime/tasks.pyi +0 -41
  106. erispulse-2.6.3.dev0/src/ErisPulse/sdk.pyi +0 -259
  107. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/.gitignore +0 -0
  108. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/LICENSE +0 -0
  109. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/README.pypi.md +0 -0
  110. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/__init__.py +0 -0
  111. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/base.py +0 -0
  112. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/cli.py +0 -0
  113. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/__init__.py +0 -0
  114. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/init.py +0 -0
  115. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/install.py +0 -0
  116. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/language.py +0 -0
  117. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/list.py +0 -0
  118. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/list_remote.py +0 -0
  119. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/run.py +0 -0
  120. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/self_update.py +0 -0
  121. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/types.py +0 -0
  122. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/uninstall.py +0 -0
  123. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/commands/upgrade.py +0 -0
  124. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/console.py +0 -0
  125. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/hints.py +0 -0
  126. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/__init__.py +0 -0
  127. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/__init__.py +0 -0
  128. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/en.py +0 -0
  129. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/ja.py +0 -0
  130. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/ru.py +0 -0
  131. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/zh_cn.py +0 -0
  132. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/i18n/locales/zh_tw.py +0 -0
  133. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/registry.py +0 -0
  134. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/utils/__init__.py +0 -0
  135. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/utils/display.py +0 -0
  136. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/utils/file_watcher.py +0 -0
  137. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/CLI/utils/package_manager.py +0 -0
  138. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/client.py +0 -0
  139. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/errors.py +0 -0
  140. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/kv_builder.py +0 -0
  141. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/manager.py +0 -0
  142. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/router.py +0 -0
  143. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/send_builder.py +0 -0
  144. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/send_rules.py +0 -0
  145. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/storage.py +0 -0
  146. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Bases/websocket.py +0 -0
  147. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/__init__.py +0 -0
  148. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/base.py +0 -0
  149. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/command.py +0 -0
  150. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/message.py +0 -0
  151. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/message_builder.py +0 -0
  152. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/meta.py +0 -0
  153. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/notice.py +0 -0
  154. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/request.py +0 -0
  155. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/session_type.py +0 -0
  156. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/Event/wrapper.py +0 -0
  157. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/__init__.py +0 -0
  158. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/__init__.py +0 -0
  159. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/error.css +0 -0
  160. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/error.html +0 -0
  161. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/root.css +0 -0
  162. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/assets/root.html +0 -0
  163. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/client.py +0 -0
  164. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/config.py +0 -0
  165. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/__init__.py +0 -0
  166. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/constants.py +0 -0
  167. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/__init__.py +0 -0
  168. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/en.py +0 -0
  169. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/ja.py +0 -0
  170. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/ru.py +0 -0
  171. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/zh_cn.py +0 -0
  172. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/i18n/locales/zh_tw.py +0 -0
  173. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/lifecycle.py +0 -0
  174. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/logger.py +0 -0
  175. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/master.py +0 -0
  176. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/router.py +0 -0
  177. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/Core/storage.py +0 -0
  178. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/__init__.py +0 -0
  179. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/__main__.py +0 -0
  180. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/__init__.py +0 -0
  181. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/adapter.py +0 -0
  182. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/bases/__init__.py +0 -0
  183. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/bases/finder.py +0 -0
  184. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/finders/module.py +0 -0
  185. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/__init__.py +0 -0
  186. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/adapter.py +0 -0
  187. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/bases/__init__.py +0 -0
  188. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/bases/loader.py +0 -0
  189. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/module.py +0 -0
  190. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/strategy.py +0 -0
  191. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/loaders/strict.py +0 -0
  192. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/py.typed +0 -0
  193. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/context.py +0 -0
  194. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/exceptions.py +0 -0
  195. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/frame_config.py +0 -0
  196. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/hints.py +0 -0
  197. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/runtime/tasks.py +0 -0
  198. {erispulse-2.6.3.dev0 → erispulse-2.7.0.dev0}/src/ErisPulse/sdk.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 2.6.3.dev0
3
+ Version: 2.7.0.dev0
4
4
  Summary: Event-driven modular async bot framework — write once, deploy to any platform | 事件驱动的模块化异步机器人框架,一次编写,多平台部署
5
5
  Project-URL: Homepage, https://github.com/ErisPulse/ErisPulse
6
6
  Project-URL: Documentation, https://www.erisdev.com#docs
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ErisPulse"
7
- version = "2.6.3-dev.0"
7
+ version = "2.7.0-dev0"
8
8
  description = "Event-driven modular async bot framework — write once, deploy to any platform | 事件驱动的模块化异步机器人框架,一次编写,多平台部署"
9
9
  readme = "README.pypi.md"
10
10
  requires-python = ">=3.10"
@@ -63,9 +63,8 @@ _MODULE_INIT = """from .Core import Main
63
63
  """
64
64
 
65
65
  _MODULE_CORE = """from dataclasses import dataclass, field
66
- from ErisPulse.Core.Bases import BaseModule
66
+ from ErisPulse.Core.Bases import BaseConfig, BaseI18n, BaseModule, I18nKey
67
67
  from ErisPulse.Core.Event import command, message, notice
68
- from ErisPulse.runtime.config_schema import BaseConfig
69
68
 
70
69
 
71
70
  @dataclass
@@ -79,6 +78,20 @@ class {name}Config(BaseConfig):
79
78
  )
80
79
 
81
80
 
81
+ class {name}I18n(BaseI18n):
82
+ \"\"\"{name} 模块翻译键声明
83
+
84
+ 声明的翻译键会被框架自动注册到 i18n 系统。
85
+ 键路径自动生成为: <模块名>.<属性名>
86
+ \"\"\"
87
+ # 示例:取消注释并修改以启用
88
+ # welcome: I18nKey = I18nKey(
89
+ # default="Welcome to {name}!",
90
+ # zh_CN="欢迎使用 {name}!",
91
+ # en="Welcome to {name}!",
92
+ # )
93
+
94
+
82
95
  class Main(BaseModule):
83
96
  \"\"\"
84
97
  {name}模块
@@ -87,6 +100,7 @@ class Main(BaseModule):
87
100
  \"\"\"
88
101
 
89
102
  ConfigClass = {name}Config
103
+ I18nClass = {name}I18n
90
104
 
91
105
  def __init__(self, sdk=None):
92
106
  from ErisPulse import sdk as _sdk
@@ -179,7 +193,7 @@ _ADAPTER_CORE = """import asyncio
179
193
  import json
180
194
  from dataclasses import dataclass, field
181
195
  from ErisPulse.Core import BaseAdapter
182
- from ErisPulse.runtime.config_schema import BaseConfig
196
+ from ErisPulse.Core.Bases import BaseConfig, I18nKey, I18nKeys
183
197
  from ErisPulse.Core import router
184
198
 
185
199
 
@@ -205,6 +219,31 @@ class {name}Config(BaseConfig):
205
219
  )
206
220
 
207
221
 
222
+ class {name}I18n(BaseI18n):
223
+ \"\"\"{name} 适配器翻译键声明
224
+
225
+ 声明的翻译键会被框架自动注册到 i18n 系统。
226
+ 这里集中管理适配器用到的所有翻译键(含配置描述引用的键)。
227
+ \"\"\"
228
+ # 注册配置描述中引用的 i18n 键的多语言译文
229
+ endpoint: I18nKey = I18nKey(
230
+ default="Platform API Endpoint",
231
+ zh_CN="平台 API 地址",
232
+ en="Platform API Endpoint",
233
+ ja="APIアドレス",
234
+ ru="API адрес",
235
+ zh_TW="API 位址",
236
+ )
237
+ token: I18nKey = I18nKey(
238
+ default="Platform Token",
239
+ zh_CN="平台 Token",
240
+ en="Platform Token",
241
+ ja="トークン",
242
+ ru="Токен",
243
+ zh_TW="權杖",
244
+ )
245
+
246
+
208
247
  class {name}(BaseAdapter):
209
248
  \"\"\"
210
249
  {name} 适配器
@@ -214,6 +253,7 @@ class {name}(BaseAdapter):
214
253
  \"\"\"
215
254
 
216
255
  ConfigClass = {name}Config
256
+ I18nClass = {name}I18n
217
257
 
218
258
  def __init__(self, sdk=None):
219
259
  super().__init__()
@@ -23,21 +23,41 @@ from .websocket import WebSocketConnectionBase, WSMessage
23
23
  from .router import HttpRequest, WebSocketConnection, SseEmitter
24
24
  from .client import BaseHttpClient, BaseHttpResponse, BaseClientWebSocket
25
25
 
26
+ # 配置 / i18n Schema 类型
27
+ from .config_schema import (
28
+ AdapterConfig,
29
+ BaseConfig,
30
+ BotAccountConfig,
31
+ )
32
+ from .i18n_schema import (
33
+ BaseI18n,
34
+ I18nKey,
35
+ key,
36
+ )
37
+
26
38
  __all__ = [
39
+ # 配置 Schema 别名(= BaseConfig)
40
+ "AdapterConfig",
27
41
  "BaseAdapter",
28
42
  "BaseClientWebSocket",
43
+ "BaseConfig",
29
44
  "BaseHttpClient",
30
45
  "BaseHttpResponse",
46
+ # i18n 键声明 Schema 基类(命名对齐 BaseConfig)
47
+ "BaseI18n",
31
48
  "BaseModule",
32
49
  "BaseQueryBuilder",
33
50
  "BaseStorage",
34
51
  "BatchContext",
52
+ "BotAccountConfig",
35
53
  "ClientConnectionError",
36
54
  "ClientError",
37
55
  "ClientTimeoutError",
38
56
  "ErisPulseError",
39
57
  "HTTPStatusError",
40
58
  "HttpRequest",
59
+ # i18n 单键声明
60
+ "I18nKey",
41
61
  "KVQueryBuilder",
42
62
  "RequestDSL",
43
63
  "SendBuilder",
@@ -965,11 +965,14 @@ class BaseAdapter(ABC):
965
965
  7. 通过 self.cfg / self.accounts 访问类型安全的配置对象(实时读取)
966
966
  8. 通过 self.emit_meta() 发送 meta 事件
967
967
  9. 通过 self.make_response() / self.make_error() 构造标准化响应
968
+ 10. 通过 I18nClass 声明翻译键集合,框架自动注册到 i18n 系统
968
969
  {!--< /tips >!--}
969
970
  """
970
971
 
971
972
  ConfigClass: type | None = None
972
973
  AccountConfigClass: type | None = None
974
+ I18nClass: type | None = None
975
+ EventMixin: type | None = None
973
976
 
974
977
  _platform: str = ""
975
978
  _sdk: Any = None
@@ -1105,6 +1108,10 @@ class BaseAdapter(ABC):
1105
1108
  self._config_instance = None
1106
1109
  self._accounts_data = None
1107
1110
 
1111
+ # 注册 I18nClass 中声明的翻译键(在生成配置之前)
1112
+ self._ensure_i18n_registered()
1113
+ # EventMixin 的注册由 AdapterManager 在注入 _platform 后调用
1114
+
1108
1115
  # 初始化时确保配置模板存在
1109
1116
  if self.ConfigClass is not None:
1110
1117
  self._ensure_config_exists()
@@ -1196,8 +1203,11 @@ class BaseAdapter(ABC):
1196
1203
  "未声明 ConfigClass,请设置 MyAdapter.ConfigClass = MyConfig"
1197
1204
  )
1198
1205
 
1199
- from ...runtime.config_schema import dict_to_dataclass
1200
1206
  from ..config import config as config_mgr
1207
+ from .config_schema import dict_to_dataclass
1208
+
1209
+ # 适配器的 EventMixin 在 AdapterManager.register() 注入 _platform 后注册
1210
+ # __init__ 阶段 _platform 尚未注入,因此不在此处调用
1201
1211
 
1202
1212
  data = config_mgr.getConfig(self._get_config_key())
1203
1213
  if data is None:
@@ -1248,8 +1258,8 @@ class BaseAdapter(ABC):
1248
1258
  "未声明 AccountConfigClass,请设置 MyAdapter.AccountConfigClass = MyBotConfig"
1249
1259
  )
1250
1260
 
1251
- from ...runtime.config_schema import dict_to_dataclass, validate_config
1252
1261
  from ..config import config as config_mgr
1262
+ from .config_schema import dict_to_dataclass, validate_config
1253
1263
 
1254
1264
  key = f"{self._get_config_key()}.accounts"
1255
1265
  data = config_mgr.getConfig(key)
@@ -1334,15 +1344,20 @@ class BaseAdapter(ABC):
1334
1344
  确保全局配置模板存在,不存在则生成默认配置
1335
1345
 
1336
1346
  {!--< internal-use >!--}
1347
+ 会先行调用 _ensure_i18n_registered() 注册声明的翻译键,
1348
+ 确保配置描述引用的 i18n 键在生成模板时已可用。
1337
1349
  {!--< /internal-use >!--}
1338
1350
  """
1351
+ # 先行注册 i18n 键(在生成配置之前),保证配置描述中的 i18n 键可用
1352
+ self._ensure_i18n_registered()
1353
+
1339
1354
  if self.ConfigClass is None:
1340
1355
  return
1341
- from ...runtime.config_schema import (
1356
+ from ..config import config as config_mgr
1357
+ from .config_schema import (
1342
1358
  dataclass_to_defaults_dict,
1343
1359
  dataclass_to_toml_with_comments,
1344
1360
  )
1345
- from ..config import config as config_mgr
1346
1361
 
1347
1362
  key = self._get_config_key()
1348
1363
  data = config_mgr.getConfig(key)
@@ -1353,6 +1368,63 @@ class BaseAdapter(ABC):
1353
1368
  config_mgr.setConfig(key, data, immediate=True)
1354
1369
  self._get_logger().info(f"已生成 {key} 默认配置模板:\n{toml_str}")
1355
1370
 
1371
+ def _ensure_i18n_registered(self):
1372
+ """
1373
+ 注册 I18nClass 中声明的翻译键到 i18n 系统
1374
+
1375
+ 使用适配器配置键名(默认为类名)作为键名前缀和 domain,便于统一卸载。
1376
+ 方法是幂等的,多次调用不会产生副作用(重复注册会覆盖旧值)。
1377
+
1378
+ {!--< internal-use >!--}
1379
+ 由 __init__() 在生成配置之前隐式调用。
1380
+ {!--< /internal-use >!--}
1381
+ """
1382
+ if self.I18nClass is None:
1383
+ return
1384
+ from .i18n_schema import BaseI18n
1385
+
1386
+ if not isinstance(self.I18nClass, type) or not issubclass(self.I18nClass, BaseI18n):
1387
+ # 非法声明静默跳过(避免影响适配器初始化流程)
1388
+ return
1389
+
1390
+ prefix = f"{self._get_config_key()}."
1391
+ domain = self._get_config_key()
1392
+ try:
1393
+ self.I18nClass.register(prefix=prefix, domain=domain)
1394
+ except Exception:
1395
+ # i18n 注册失败不应中断适配器初始化
1396
+ self._get_logger().debug(
1397
+ f"{self.__class__.__name__}.I18nClass.register() 失败",
1398
+ exc_info=True,
1399
+ )
1400
+
1401
+ def _ensure_event_mixin_registered(self):
1402
+ """
1403
+ 注册 EventMixin 中声明的事件扩展方法
1404
+
1405
+ 适配器声明 ``EventMixin`` 时,框架自动将其注册到适配器的平台
1406
+ (即 ``self._platform``),而不是通配符。
1407
+
1408
+ {!--< internal-use >!--}
1409
+ 由 __init__() 隐式调用。
1410
+ {!--< /internal-use >!--}
1411
+ """
1412
+ if self.EventMixin is None:
1413
+ return
1414
+ if not isinstance(self.EventMixin, type):
1415
+ return
1416
+
1417
+ from ..Event import register_event_mixin
1418
+
1419
+ platform = self._platform or "*"
1420
+ try:
1421
+ register_event_mixin(platform, self.EventMixin)
1422
+ except Exception:
1423
+ self._get_logger().debug(
1424
+ f"{self.__class__.__name__}.EventMixin 注册失败",
1425
+ exc_info=True,
1426
+ )
1427
+
1356
1428
  def _ensure_accounts_exist(self):
1357
1429
  """
1358
1430
  确保多账户配置模板存在,不存在则生成默认账户配置
@@ -1362,8 +1434,8 @@ class BaseAdapter(ABC):
1362
1434
  """
1363
1435
  if self.AccountConfigClass is None:
1364
1436
  return
1365
- from ...runtime.config_schema import dataclass_to_defaults_dict
1366
1437
  from ..config import config as config_mgr
1438
+ from .config_schema import dataclass_to_defaults_dict
1367
1439
 
1368
1440
  key = f"{self._get_config_key()}.accounts"
1369
1441
  data = config_mgr.getConfig(key)
@@ -78,7 +78,15 @@ def _get_ui_meta(meta: Mapping | None) -> dict:
78
78
 
79
79
 
80
80
  def _type_default(type_hint) -> object:
81
- """根据类型注解返回合理的默认值"""
81
+ """
82
+ 根据类型注解返回合理的默认值
83
+
84
+ {!--< internal-use >!--}
85
+ {!--< /internal-use >!--}
86
+
87
+ :param type_hint: Python 类型注解
88
+ :return: 对应类型的默认值(int→0, float→0.0, bool→False, list→[], dict→{}, str→"")
89
+ """
82
90
  type_str = str(type_hint).lower()
83
91
  if "int" in type_str:
84
92
  return 0
@@ -94,7 +102,15 @@ def _type_default(type_hint) -> object:
94
102
 
95
103
 
96
104
  def _python_type_to_toml_type(type_hint) -> str:
97
- """将 Python 类型注解转为 TOML 类型字符串"""
105
+ """
106
+ 将 Python 类型注解转为 TOML 类型字符串
107
+
108
+ {!--< internal-use >!--}
109
+ {!--< /internal-use >!--}
110
+
111
+ :param type_hint: Python 类型注解
112
+ :return: TOML 类型名(integer/float/boolean/array/table/string)
113
+ """
98
114
  type_str = str(type_hint).lower()
99
115
  if "int" in type_str:
100
116
  return "integer"
@@ -110,7 +126,15 @@ def _python_type_to_toml_type(type_hint) -> str:
110
126
 
111
127
 
112
128
  def _format_toml_value(value) -> str:
113
- """将 Python 值格式化为 TOML 值字符串"""
129
+ """
130
+ 将 Python 值格式化为 TOML 值字符串
131
+
132
+ {!--< internal-use >!--}
133
+ {!--< /internal-use >!--}
134
+
135
+ :param value: Python 值(str/int/float/bool/list/dict 等)
136
+ :return: TOML 格式的字符串
137
+ """
114
138
  if isinstance(value, bool):
115
139
  return "true" if value else "false"
116
140
  if isinstance(value, int):
@@ -129,7 +153,15 @@ def _format_toml_value(value) -> str:
129
153
 
130
154
 
131
155
  def _get_field_default(f):
132
- """获取字段的默认值"""
156
+ """
157
+ 获取 dataclass 字段的默认值
158
+
159
+ {!--< internal-use >!--}
160
+ {!--< /internal-use >!--}
161
+
162
+ :param f: dataclass Field 对象
163
+ :return: 字段的默认值(优先 default,其次 default_factory,最后根据类型推断)
164
+ """
133
165
  if f.default is not MISSING:
134
166
  return f.default
135
167
  if f.default_factory is not MISSING:
@@ -138,7 +170,15 @@ def _get_field_default(f):
138
170
 
139
171
 
140
172
  def _is_empty(value) -> bool:
141
- """判断值是否为空"""
173
+ """
174
+ 判断值是否为空(None / 空字符串 / 空列表 / 空字典)
175
+
176
+ {!--< internal-use >!--}
177
+ {!--< /internal-use >!--}
178
+
179
+ :param value: 任意值
180
+ :return: 是否为空
181
+ """
142
182
  if value is None:
143
183
  return True
144
184
  if isinstance(value, str) and value.strip() == "":
@@ -147,7 +187,16 @@ def _is_empty(value) -> bool:
147
187
 
148
188
 
149
189
  def _coerce_value(value, type_hint):
150
- """将值强制转换为目标类型"""
190
+ """
191
+ 将值强制转换为目标类型(如 str→int、str→bool)
192
+
193
+ {!--< internal-use >!--}
194
+ {!--< /internal-use >!--}
195
+
196
+ :param value: 原始值
197
+ :param type_hint: 目标类型注解
198
+ :return: 转换后的值(转换失败时返回原值)
199
+ """
151
200
  if value is None:
152
201
  return value
153
202
 
@@ -465,27 +514,24 @@ def register_config_i18n(
465
514
  调用 i18n.register() 注册翻译。
466
515
 
467
516
  两种用法:
468
- 1. 自动模式(translations=None):将字段 description.default 作为 zh-CN 翻译注册
517
+ 1. 自动模式(translations=None):将字段 description.default 注册到指定 lang
518
+ (description.default 是语言无关的兜底文本,调用者自行决定注册到哪种语言)
469
519
  2. 手动模式:提供 translations 字典({i18n_key: translated_text})
470
520
 
471
521
  使用示例::
472
522
 
473
- # 自动注册默认值作为中文翻译
523
+ # 将默认文本注册为中文翻译
474
524
  register_config_i18n(MyAdapterConfig, "zh-CN")
475
525
 
476
- # 手动注册英文翻译
526
+ # 将默认文本注册为英文翻译
527
+ register_config_i18n(MyAdapterConfig, "en")
528
+
529
+ # 手动提供英文翻译(覆盖默认文本)
477
530
  register_config_i18n(MyAdapterConfig, "en", {
478
531
  "my_adapter.endpoint": "API Endpoint",
479
532
  "my_adapter.token": "Platform Token",
480
533
  })
481
534
 
482
- # 多账户配置同理
483
- register_config_i18n(MyBotConfig, "zh-CN")
484
- register_config_i18n(MyBotConfig, "en", {
485
- "my_adapter.bot_id": "Bot ID",
486
- "my_adapter.bot_token": "Bot Token",
487
- })
488
-
489
535
  :param config_class: dataclass 配置类
490
536
  :param lang: 语言代码(如 "zh-CN", "en")
491
537
  :param translations: 手动提供的翻译字典,None 则自动提取
@@ -0,0 +1,239 @@
1
+ """
2
+ ErisPulse i18n 键声明 Schema 模块
3
+
4
+ 提供基于类属性的 i18n 翻译键声明,支持框架自动注册。
5
+ 适用于适配器、模块、外部项目等任何需要批量声明翻译键的场景。
6
+
7
+ {!--< tips >!--}
8
+ 1. 继承 BaseI18n 基类,通过类属性声明翻译键(命名与 BaseConfig 对齐)
9
+ 2. 每个属性对应一个翻译键,属性名(加模块前缀)作为键路径
10
+ 3. 也可通过 I18nKey(key=...) 显式指定完整键路径
11
+ 4. 框架在加载模块/适配器时自动注册所有声明的翻译键
12
+ 5. 配合 BaseModule.I18nClass / BaseAdapter.I18nClass 使用,无需手动调用 i18n.register()
13
+ 6. ``default`` 是语言无关的兜底文本,不会注册到任何语言;
14
+ 要让翻译生效,必须显式传入至少一个语言参数(``zh_CN=`` / ``en=`` 等)
15
+ {!--< /tips >!--}
16
+ """
17
+
18
+
19
+ class I18nKey:
20
+ """
21
+ 单个 i18n 翻译键的声明
22
+
23
+ :param default: 兜底文本(语言无关)。当所有已注册语言均未覆盖此键时,
24
+ 作为最后的显示文本。**不会注册到任何语言**。
25
+ 各国开发者可使用自己母语填写此字段,框架不做任何假设。
26
+ :param key: 完整的翻译键路径(如 ``"mymodule.welcome"``)。
27
+ 省略时使用属性名 + 调用方提供的前缀自动生成。
28
+ :param zh_CN: 简体中文翻译
29
+ :param zh_TW: 繁体中文翻译
30
+ :param en: 英文翻译
31
+ :param ja: 日文翻译
32
+ :param ru: 俄文翻译
33
+
34
+ 使用示例::
35
+
36
+ from ErisPulse.Core.Bases import BaseI18n, I18nKey
37
+
38
+ class MyModule(BaseModule):
39
+ class I18nClass(BaseI18n):
40
+ # 自动生成键: mymodule.welcome
41
+ welcome: I18nKey = I18nKey(
42
+ default="Welcome", # 语言无关的兜底
43
+ zh_CN="欢迎",
44
+ zh_TW="歡迎",
45
+ en="Welcome",
46
+ ja="ようこそ",
47
+ ru="Добро пожаловать",
48
+ )
49
+
50
+ # 显式指定键路径
51
+ deep: I18nKey = I18nKey(
52
+ key="mymodule.deep.nested.key",
53
+ default="Default text",
54
+ zh_CN="默认文本",
55
+ zh_TW="預設文本",
56
+ en="Default text",
57
+ ja="デフォルトテキスト",
58
+ ru="Текст по умолчанию",
59
+ )
60
+ """
61
+
62
+ __slots__ = ("_key", "default", "translations")
63
+
64
+ def __init__(
65
+ self,
66
+ default: str,
67
+ *,
68
+ key: str | None = None,
69
+ zh_CN: str | None = None,
70
+ zh_TW: str | None = None,
71
+ en: str | None = None,
72
+ ja: str | None = None,
73
+ ru: str | None = None,
74
+ ):
75
+ if not default:
76
+ raise ValueError("default 是必填项(语言无关的兜底文本)")
77
+
78
+ self._key = key
79
+ self.default = default
80
+ # translations 只包含显式声明的语言翻译
81
+ # default 不注册到任何语言
82
+ self.translations: dict[str, str] = {}
83
+ if zh_CN is not None:
84
+ self.translations["zh-CN"] = zh_CN
85
+ if zh_TW is not None:
86
+ self.translations["zh-TW"] = zh_TW
87
+ if en is not None:
88
+ self.translations["en"] = en
89
+ if ja is not None:
90
+ self.translations["ja"] = ja
91
+ if ru is not None:
92
+ self.translations["ru"] = ru
93
+
94
+ @property
95
+ def explicit_key(self) -> str | None:
96
+ """
97
+ 获取显式指定的键路径(如有)
98
+
99
+ :return: 显式键名字符串,或 None 表示使用前缀+属性名自动生成
100
+ """
101
+ return self._key
102
+
103
+ def __repr__(self) -> str:
104
+ return (
105
+ f"I18nKey(key={self._key!r}, default={self.default!r}, "
106
+ f"langs={sorted(self.translations.keys())})"
107
+ )
108
+
109
+
110
+ # 模块级别名,方便在类定义中使用更短的名称
111
+ # 使用示例::
112
+ # class MyKeys(BaseI18n):
113
+ # hello = key(default="Hello", en="Hello", zh_CN="你好")
114
+ key = I18nKey
115
+
116
+
117
+ class BaseI18n:
118
+ """
119
+ i18n 键声明集合的基类
120
+
121
+ 命名与 :class:`BaseConfig` 对齐:用户通过嵌套类继承此类声明翻译键,
122
+ 框架会在模块/适配器加载时自动调用 :meth:`register` 将所有声明的翻译键
123
+ 注册到 i18n 系统。
124
+
125
+ {!--< tips >!--}
126
+ 1. 类属性必须是 :class:`I18nKey` 实例,否则被忽略
127
+ 2. 属性名以下划线开头的会被忽略(视为私有/内部)
128
+ 3. 自动生成的键路径为 ``<前缀><属性名>``,前缀通常是模块名 + ``.``
129
+ 4. 通过 :class:`I18nKey` 的 ``key=`` 参数可显式指定完整键路径
130
+ 5. 同一 domain 可被多次注册,键值会被覆盖更新
131
+ 6. ``I18nKey.default`` 是语言无关的兜底文本,不参与注册;
132
+ 实际翻译必须通过 ``zh_CN=`` / ``en=`` 等参数显式声明
133
+ {!--< /tips >!--}
134
+
135
+ 使用示例::
136
+
137
+ from ErisPulse.Core.Bases import BaseModule, BaseI18n, I18nKey
138
+
139
+ class MyModule(BaseModule):
140
+ class I18nClass(BaseI18n):
141
+ welcome: I18nKey = I18nKey(
142
+ default="Welcome",
143
+ zh_CN="欢迎",
144
+ zh_TW="歡迎",
145
+ en="Welcome",
146
+ ja="ようこそ",
147
+ ru="Добро пожаловать",
148
+ )
149
+ goodbye: I18nKey = I18nKey(
150
+ default="Bye",
151
+ zh_CN="再见",
152
+ zh_TW="再見",
153
+ en="Goodbye",
154
+ ja="さようなら",
155
+ ru="До свидания",
156
+ )
157
+
158
+ 也可独立使用(手动注册)::
159
+
160
+ class MyKeys(BaseI18n):
161
+ hello: I18nKey = I18nKey(
162
+ default="Hello",
163
+ zh_CN="你好",
164
+ zh_TW="你好",
165
+ en="Hello",
166
+ ja="こんにちは",
167
+ ru="Привет",
168
+ )
169
+
170
+ MyKeys.register(prefix="myapp.", domain="myapp")
171
+ """
172
+
173
+ @classmethod
174
+ def _collect_keys(cls) -> dict[str, I18nKey]:
175
+ """
176
+ 收集类中所有声明的 I18nKey
177
+
178
+ 遍历 MRO(含父类继承),收集所有非下划线开头的 I18nKey 类属性。
179
+ 子类同名属性会覆盖父类(与 Python 属性查找语义一致)。
180
+
181
+ :return: ``{属性名: I18nKey 实例}`` 字典
182
+ """
183
+ keys: dict[str, I18nKey] = {}
184
+ # 反向遍历 MRO,让子类覆盖父类
185
+ for klass in reversed(cls.__mro__):
186
+ for name, value in vars(klass).items():
187
+ if name.startswith("_"):
188
+ continue
189
+ if isinstance(value, I18nKey):
190
+ keys[name] = value
191
+ return keys
192
+
193
+ @classmethod
194
+ def register(cls, prefix: str = "", domain: str = "app") -> int:
195
+ """
196
+ 注册所有翻译键到 i18n 系统
197
+
198
+ 仅注册 :class:`I18nKey` 中显式声明的语言翻译。
199
+ ``default`` 字段是语言无关的兜底文本,不参与注册。
200
+
201
+ :param prefix: 键名前缀(通常是模块名 + ``.``,如 ``"mymodule."``)。
202
+ 仅对未显式指定 ``key`` 的翻译键生效。
203
+ :param domain: i18n 域标识,用于卸载时按域统一清理。
204
+ 建议使用模块名。
205
+ :return: 注册的翻译条目总数
206
+
207
+ :example:
208
+ >>> class MyKeys(BaseI18n):
209
+ ... hello: I18nKey = I18nKey(
210
+ ... default="Hello",
211
+ ... zh_CN="你好",
212
+ ... en="Hello",
213
+ ... )
214
+ >>> MyKeys.register(prefix="myapp.", domain="myapp")
215
+ 2 # zh-CN + en
216
+ """
217
+ from ..i18n import i18n
218
+
219
+ count = 0
220
+ for attr_name, i18n_key in cls._collect_keys().items():
221
+ # 决定最终的 key 路径:显式 key > 前缀 + 属性名
222
+ final_key = i18n_key.explicit_key or f"{prefix}{attr_name}"
223
+
224
+ for lang, text in i18n_key.translations.items():
225
+ i18n.register(lang, {final_key: text}, domain=domain)
226
+ count += 1
227
+
228
+ return count
229
+
230
+
231
+ # ---------------------------------------------------------------------------
232
+ # 导出
233
+ # ---------------------------------------------------------------------------
234
+
235
+ __all__ = [
236
+ "BaseI18n",
237
+ "I18nKey",
238
+ "key",
239
+ ]