mindroot 9.2.0__py3-none-any.whl → 9.5.0__py3-none-any.whl
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.
- mindroot/coreplugins/admin/__init__.py +3 -1
- mindroot/coreplugins/admin/agent_router.py +250 -7
- mindroot/coreplugins/admin/asset_manager.py +164 -0
- mindroot/coreplugins/admin/command_router.py +236 -1
- mindroot/coreplugins/admin/mcp_catalog_routes.py +156 -0
- mindroot/coreplugins/admin/mcp_publish_routes.py +450 -0
- mindroot/coreplugins/admin/mcp_registry_routes.py +495 -0
- mindroot/coreplugins/admin/mcp_routes.py +216 -0
- mindroot/coreplugins/admin/mod.py +62 -0
- mindroot/coreplugins/admin/oauth_callback_router.py +84 -0
- mindroot/coreplugins/admin/persona_handler.py +15 -6
- mindroot/coreplugins/admin/persona_router.py +158 -2
- mindroot/coreplugins/admin/plugin_manager.py +63 -0
- mindroot/coreplugins/admin/plugin_router.py +1 -1
- mindroot/coreplugins/admin/plugin_router_fixed.py +23 -0
- mindroot/coreplugins/admin/plugin_router_new_not_working.py +145 -0
- mindroot/coreplugins/admin/plugin_routes.py +114 -0
- mindroot/coreplugins/admin/registry_settings_routes.py +140 -0
- mindroot/coreplugins/admin/router.py +116 -15
- mindroot/coreplugins/admin/service_models.py +1 -1
- mindroot/coreplugins/admin/settings_router.py +1 -0
- mindroot/coreplugins/admin/static/css/admin-custom.css +357 -2
- mindroot/coreplugins/admin/static/css/dark.css +1 -0
- mindroot/coreplugins/admin/static/css/default.css +4 -0
- mindroot/coreplugins/admin/static/js/about-info.js +367 -0
- mindroot/coreplugins/admin/static/js/agent-form.js +83 -3
- mindroot/coreplugins/admin/static/js/api-key-script.js +307 -0
- mindroot/coreplugins/admin/static/js/mcp-manager.js +348 -0
- mindroot/coreplugins/admin/static/js/mcp-publisher.js +780 -0
- mindroot/coreplugins/admin/static/js/persona-editor.js +34 -5
- mindroot/coreplugins/admin/static/js/plugin-toggle.js +1 -1
- mindroot/coreplugins/admin/static/js/recommended-plugin-install.js +63 -0
- mindroot/coreplugins/admin/static/js/registry-auth-section.js +132 -0
- mindroot/coreplugins/admin/static/js/registry-manager-base.js +613 -0
- mindroot/coreplugins/admin/static/js/registry-manager-old.js +385 -0
- mindroot/coreplugins/admin/static/js/registry-manager-publish-old-delete.js +166 -0
- mindroot/coreplugins/admin/static/js/registry-manager.js +351 -0
- mindroot/coreplugins/admin/static/js/registry-publish-section.js +377 -0
- mindroot/coreplugins/admin/static/js/registry-search-section.js +400 -0
- mindroot/coreplugins/admin/static/js/registry-search-section.js.bak +3 -0
- mindroot/coreplugins/admin/static/js/registry-settings.js +69 -0
- mindroot/coreplugins/admin/static/js/registry-shared-services.js +857 -0
- mindroot/coreplugins/admin/static/js/registry-simple-sections.js +85 -0
- mindroot/coreplugins/admin/static/js/secure-widget-manager.js +438 -0
- mindroot/coreplugins/admin/static/logo.png +0 -0
- mindroot/coreplugins/admin/templates/admin.jinja2 +275 -110
- mindroot/coreplugins/agent/Assistant/agent.json +27 -11
- mindroot/coreplugins/agent/agent.py +2 -2
- mindroot/coreplugins/agent/command_parser.py +25 -10
- mindroot/coreplugins/agent/templates/system.jinja2 +0 -12
- mindroot/coreplugins/chat/__init__.py +4 -1
- mindroot/coreplugins/chat/router.py +132 -20
- mindroot/coreplugins/chat/router_dedup_patch.py +20 -0
- mindroot/coreplugins/chat/services.py +31 -1
- mindroot/coreplugins/chat/static/css/action-fix.css +32 -0
- mindroot/coreplugins/chat/static/css/admin-custom.css +5 -3
- mindroot/coreplugins/chat/static/css/dark.css +24 -3
- mindroot/coreplugins/chat/static/css/default.css +24 -3
- mindroot/coreplugins/chat/static/css/main.css +1 -0
- mindroot/coreplugins/chat/static/js/action.js +137 -60
- mindroot/coreplugins/chat/static/js/chat-history.js +3 -0
- mindroot/coreplugins/chat/static/js/chat.js +59 -16
- mindroot/coreplugins/chat/static/js/chat.js.diff +221 -0
- mindroot/coreplugins/chat/static/js/chatform.js +2 -2
- mindroot/coreplugins/chat/static/site.webmanifest +1 -1
- mindroot/coreplugins/chat/templates/chat.jinja2 +3 -3
- mindroot/coreplugins/chat/widget_manager.py +139 -0
- mindroot/coreplugins/chat/widget_routes.py +287 -0
- mindroot/coreplugins/check_list/inject/admin.jinja2 +1 -1
- mindroot/coreplugins/email/__init__.py +2 -0
- mindroot/coreplugins/email/email_provider.py +2 -2
- mindroot/coreplugins/email/mod.py +100 -0
- mindroot/coreplugins/email/services.py +5 -3
- mindroot/coreplugins/email/smtp_handler.py +9 -3
- mindroot/coreplugins/email/test_email_service.py +75 -0
- mindroot/coreplugins/env_manager/mod.py +61 -25
- mindroot/coreplugins/home/router.py +37 -2
- mindroot/coreplugins/home/static/imgs/logo.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo.png.bak +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal2.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal_detailed.png +0 -0
- mindroot/coreplugins/home/static/imgs/logo_teal_python.png +0 -0
- mindroot/coreplugins/home/templates/home.jinja2 +15 -6
- mindroot/coreplugins/index/handlers/plugin_ops.py +1 -1
- mindroot/coreplugins/index/indices/default/index.json +6 -6
- mindroot/coreplugins/jwt_auth/middleware.py +47 -1
- mindroot/coreplugins/jwt_auth/mod.py +40 -17
- mindroot/coreplugins/l8n/__init__.py +6 -0
- mindroot/coreplugins/l8n/debug_loader.py +85 -0
- mindroot/coreplugins/l8n/debug_middleware.py +74 -0
- mindroot/coreplugins/l8n/l8n_constants.py +19 -0
- mindroot/coreplugins/l8n/language_detection.py +183 -0
- mindroot/coreplugins/l8n/middleware.py +151 -0
- mindroot/coreplugins/l8n/mod.py +277 -0
- mindroot/coreplugins/l8n/monkey_patch_to_delete.py +186 -0
- mindroot/coreplugins/l8n/test_enhanced.py +298 -0
- mindroot/coreplugins/l8n/test_l8n.py +95 -0
- mindroot/coreplugins/l8n/test_l8n_standalone.py +251 -0
- mindroot/coreplugins/l8n/test_middleware.py +272 -0
- mindroot/coreplugins/l8n/utils.py +232 -0
- mindroot/coreplugins/mcp_/__init__.py +14 -0
- mindroot/coreplugins/mcp_/catalog_commands.py +328 -0
- mindroot/coreplugins/mcp_/catalog_manager.py +263 -0
- mindroot/coreplugins/mcp_/dynamic_commands.py +154 -0
- mindroot/coreplugins/mcp_/mcp_manager.py +1031 -0
- mindroot/coreplugins/mcp_/mod.py +367 -0
- mindroot/coreplugins/mcp_/oauth_storage.py +144 -0
- mindroot/coreplugins/mcp_/server_installer.py +79 -0
- mindroot/coreplugins/mcp_/setup.py +26 -0
- mindroot/coreplugins/mcp_/test_dynamic_commands.py +134 -0
- mindroot/coreplugins/mcp_/testmcpclient.py +92 -0
- mindroot/coreplugins/persona/mod.py +12 -7
- mindroot/coreplugins/signup/templates/signup.jinja2 +1 -1
- mindroot/coreplugins/subscriptions/__init__.py +1 -0
- mindroot/coreplugins/subscriptions/mod.py +14 -3
- mindroot/coreplugins/subscriptions/router.py +3 -0
- mindroot/coreplugins/user_service/__init__.py +1 -2
- mindroot/coreplugins/user_service/admin_init.py +1 -0
- mindroot/coreplugins/user_service/email_service.py +72 -17
- mindroot/coreplugins/user_service/mod.py +10 -2
- mindroot/coreplugins/user_service/password_reset_service.py +180 -27
- mindroot/coreplugins/user_service/router.py +84 -22
- mindroot/lib/auth/api_key.py +28 -0
- mindroot/lib/cli/plugins.py +94 -0
- mindroot/lib/plugins/default_plugin_manifest.json +20 -0
- mindroot/lib/plugins/installation.py +5 -5
- mindroot/lib/plugins/l8n_static_handler.py +225 -0
- mindroot/lib/plugins/loader.py +33 -3
- mindroot/lib/plugins/loader_with_l8n.py +281 -0
- mindroot/lib/plugins/manifest.py +238 -17
- mindroot/lib/providers/commands.py +3 -1
- mindroot/lib/route_decorators.py +5 -5
- mindroot/lib/templates.py +183 -11
- mindroot/lib/utils/merge_arrays.py +1 -1
- mindroot/migrate.py +49 -0
- mindroot/registry/data_access.py +1 -1
- mindroot/server.py +47 -13
- mindroot/server_missing_normal_args.py +197 -0
- mindroot/server_prev.py +173 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/METADATA +7 -2
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/RECORD +147 -114
- mindroot/coreplugins/admin/static/favicon/about.txt +0 -6
- mindroot/coreplugins/admin/static/favicon/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/admin/static/favicon/apple-touch-icon.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon-16x16.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon-32x32.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon.ico +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/about.txt +0 -6
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon.ico +0 -0
- mindroot/coreplugins/admin/static/favicon/favicon_io (1)/site.webmanifest +0 -1
- mindroot/coreplugins/admin/static/favicon/logo.png +0 -0
- mindroot/coreplugins/admin/static/favicon/site.webmanifest +0 -1
- mindroot/coreplugins/admin/static/js/backup/agent-editor.js +0 -186
- mindroot/coreplugins/admin/static/js/backup/agent-form.js +0 -1133
- mindroot/coreplugins/admin/static/js/backup/agent-list.js +0 -94
- mindroot/coreplugins/chat/static/favicon/about.txt +0 -6
- mindroot/coreplugins/chat/static/favicon/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/chat/static/favicon/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/chat/static/favicon/apple-touch-icon.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon-16x16.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon-32x32.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon.ico +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/about.txt +0 -6
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon.ico +0 -0
- mindroot/coreplugins/chat/static/favicon/favicon_io (1)/site.webmanifest +0 -1
- mindroot/coreplugins/chat/static/favicon/logo.png +0 -0
- mindroot/coreplugins/chat/static/favicon/site.webmanifest +0 -1
- mindroot/coreplugins/index/default.json +0 -76
- mindroot/coreplugins/user_service/file_trigger_service.py +0 -72
- mindroot/coreplugins/user_service/hooks.py +0 -23
- /mindroot/coreplugins/{admin/static/favicon/android-chrome-192x192.png → home/static/imgs/backuplogo.png} +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/WHEEL +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/entry_points.txt +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-9.2.0.dist-info → mindroot-9.5.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
to_delete = """
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
# Import the translation replacement function
|
|
8
|
+
from .mod import replace_placeholders, LOCALIZED_FILES_DIR
|
|
9
|
+
|
|
10
|
+
# Import the enhanced language detection
|
|
11
|
+
from .language_detection import get_fallback_language
|
|
12
|
+
from .middleware import get_request_language
|
|
13
|
+
|
|
14
|
+
# Store original Jinja2 loader methods
|
|
15
|
+
_original_get_source = None
|
|
16
|
+
_original_loader_get_source = None
|
|
17
|
+
|
|
18
|
+
def get_current_language() -> str:
|
|
19
|
+
"""
|
|
20
|
+
Get the current language for the request using enhanced detection.
|
|
21
|
+
"""
|
|
22
|
+
return get_fallback_language(get_request_language())
|
|
23
|
+
|
|
24
|
+
def find_localized_template(template_name: str) -> Optional[Path]:
|
|
25
|
+
"""
|
|
26
|
+
Find a localized version of a template.
|
|
27
|
+
|
|
28
|
+
Uses relative path matching to find templates regardless of installation directory.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
template_name: Original template name/path
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Path to localized template if found, None otherwise
|
|
35
|
+
"""
|
|
36
|
+
if not LOCALIZED_FILES_DIR.exists():
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
# Convert template name to potential localized paths
|
|
40
|
+
template_path = Path(template_name)
|
|
41
|
+
stem = template_path.stem
|
|
42
|
+
suffix = template_path.suffix
|
|
43
|
+
|
|
44
|
+
# Create the .i18n version filename
|
|
45
|
+
localized_filename = f"{stem}.i18n{suffix}"
|
|
46
|
+
|
|
47
|
+
# Search strategies in order of preference:
|
|
48
|
+
search_strategies = [
|
|
49
|
+
# 1. Exact filename match anywhere in localized_files
|
|
50
|
+
lambda: list(LOCALIZED_FILES_DIR.rglob(localized_filename)),
|
|
51
|
+
|
|
52
|
+
# 2. Match last 2 path components
|
|
53
|
+
lambda: _find_by_path_components(template_path, localized_filename, 2),
|
|
54
|
+
|
|
55
|
+
# 3. Match last 3 path components
|
|
56
|
+
lambda: _find_by_path_components(template_path, localized_filename, 3),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
for strategy in search_strategies:
|
|
60
|
+
matches = strategy()
|
|
61
|
+
if matches:
|
|
62
|
+
# Return the first match
|
|
63
|
+
return matches[0]
|
|
64
|
+
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
def _find_by_path_components(original_path: Path, localized_filename: str, num_components: int) -> list:
|
|
68
|
+
"""
|
|
69
|
+
Find localized templates by matching the last N path components.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
original_path: Original template path
|
|
73
|
+
localized_filename: Localized filename to search for
|
|
74
|
+
num_components: Number of path components to match
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
List of matching paths
|
|
78
|
+
"""
|
|
79
|
+
if len(original_path.parts) < num_components:
|
|
80
|
+
return []
|
|
81
|
+
|
|
82
|
+
# Get the last N-1 components (excluding filename) + localized filename
|
|
83
|
+
target_components = original_path.parts[-(num_components-1):]
|
|
84
|
+
target_path_pattern = '/'.join(target_components[:-1]) + '/' + localized_filename
|
|
85
|
+
|
|
86
|
+
matches = []
|
|
87
|
+
for candidate in LOCALIZED_FILES_DIR.rglob(localized_filename):
|
|
88
|
+
candidate_relative = candidate.relative_to(LOCALIZED_FILES_DIR)
|
|
89
|
+
if str(candidate_relative).endswith(target_path_pattern):
|
|
90
|
+
matches.append(candidate)
|
|
91
|
+
|
|
92
|
+
return matches
|
|
93
|
+
|
|
94
|
+
def patched_get_source(self, environment, template):
|
|
95
|
+
"""
|
|
96
|
+
Patched version of Jinja2 loader's get_source method.
|
|
97
|
+
|
|
98
|
+
This intercepts template loading and:
|
|
99
|
+
1. Checks for localized versions
|
|
100
|
+
2. Replaces placeholders with translations
|
|
101
|
+
3. Falls back to original templates if no localized version exists
|
|
102
|
+
"""
|
|
103
|
+
# First, try to find a localized version
|
|
104
|
+
localized_path = find_localized_template(template)
|
|
105
|
+
|
|
106
|
+
if localized_path and localized_path.exists():
|
|
107
|
+
try:
|
|
108
|
+
# Read the localized template
|
|
109
|
+
with open(localized_path, 'r', encoding='utf-8') as f:
|
|
110
|
+
source = f.read()
|
|
111
|
+
|
|
112
|
+
# Replace placeholders with translations
|
|
113
|
+
current_language = get_current_language()
|
|
114
|
+
translated_source = replace_placeholders(source, current_language, str(localized_path))
|
|
115
|
+
|
|
116
|
+
# Return the translated source
|
|
117
|
+
# Note: We use the original template name for caching purposes
|
|
118
|
+
return translated_source, str(localized_path), lambda: True
|
|
119
|
+
|
|
120
|
+
except Exception as e:
|
|
121
|
+
# If there's an error reading the localized template, fall back to original
|
|
122
|
+
print(f"Error loading localized template {localized_path}: {e}")
|
|
123
|
+
|
|
124
|
+
# Fall back to original template loading
|
|
125
|
+
return _original_get_source(self, environment, template)
|
|
126
|
+
|
|
127
|
+
def install_monkey_patch():
|
|
128
|
+
"""
|
|
129
|
+
Install the monkey patch for Jinja2 template loading.
|
|
130
|
+
|
|
131
|
+
This patches the FileSystemLoader.get_source method to intercept
|
|
132
|
+
template loading and provide localized versions when available.
|
|
133
|
+
"""
|
|
134
|
+
global _original_get_source
|
|
135
|
+
return
|
|
136
|
+
try:
|
|
137
|
+
from jinja2 import FileSystemLoader
|
|
138
|
+
|
|
139
|
+
# Store the original method
|
|
140
|
+
if _original_get_source is None:
|
|
141
|
+
_original_get_source = FileSystemLoader.get_source
|
|
142
|
+
|
|
143
|
+
# Install the patch
|
|
144
|
+
FileSystemLoader.get_source = patched_get_source
|
|
145
|
+
|
|
146
|
+
print("L8n monkey patch installed successfully")
|
|
147
|
+
return True
|
|
148
|
+
|
|
149
|
+
except ImportError:
|
|
150
|
+
print("Warning: Could not import Jinja2 for monkey patching")
|
|
151
|
+
return False
|
|
152
|
+
except Exception as e:
|
|
153
|
+
print(f"Error installing l8n monkey patch: {e}")
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
def uninstall_monkey_patch():
|
|
157
|
+
"""
|
|
158
|
+
Remove the monkey patch and restore original Jinja2 behavior.
|
|
159
|
+
"""
|
|
160
|
+
global _original_get_source
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
from jinja2 import FileSystemLoader
|
|
164
|
+
|
|
165
|
+
if _original_get_source is not None:
|
|
166
|
+
FileSystemLoader.get_source = _original_get_source
|
|
167
|
+
print("L8n monkey patch removed successfully")
|
|
168
|
+
return True
|
|
169
|
+
else:
|
|
170
|
+
print("No monkey patch to remove")
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
except ImportError:
|
|
174
|
+
print("Warning: Could not import Jinja2 for monkey patch removal")
|
|
175
|
+
return False
|
|
176
|
+
except Exception as e:
|
|
177
|
+
print(f"Error removing l8n monkey patch: {e}")
|
|
178
|
+
return False
|
|
179
|
+
|
|
180
|
+
# Auto-install the monkey patch when this module is imported
|
|
181
|
+
# Prevent double installation by checking if already installed
|
|
182
|
+
if __name__ != '__main__' and not hasattr(install_monkey_patch, '_auto_installed'):
|
|
183
|
+
install_monkey_patch()
|
|
184
|
+
install_monkey_patch._auto_installed = True
|
|
185
|
+
|
|
186
|
+
"""
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Enhanced test script for the l8n localization plugin with language detection.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import asyncio
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
# Add the current directory to Python path for imports
|
|
12
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
13
|
+
|
|
14
|
+
from test_l8n_standalone import (
|
|
15
|
+
write_localized_file,
|
|
16
|
+
set_translations,
|
|
17
|
+
replace_placeholders,
|
|
18
|
+
TRANSLATIONS
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
from language_detection import (
|
|
22
|
+
get_current_language_from_request,
|
|
23
|
+
get_fallback_language,
|
|
24
|
+
set_language_for_request,
|
|
25
|
+
get_supported_languages,
|
|
26
|
+
is_language_supported,
|
|
27
|
+
_parse_accept_language_header
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
async def test_language_detection():
|
|
31
|
+
"""Test the enhanced language detection functionality."""
|
|
32
|
+
print("Testing Enhanced Language Detection...\n")
|
|
33
|
+
|
|
34
|
+
# Test 1: Default language detection
|
|
35
|
+
print("1. Testing default language detection...")
|
|
36
|
+
default_lang = get_current_language_from_request()
|
|
37
|
+
print(f" Default language: {default_lang}")
|
|
38
|
+
|
|
39
|
+
# Test 2: Environment variable override
|
|
40
|
+
print("\n2. Testing environment variable override...")
|
|
41
|
+
os.environ['MINDROOT_LANGUAGE'] = 'es'
|
|
42
|
+
env_lang = get_current_language_from_request()
|
|
43
|
+
print(f" Language with MINDROOT_LANGUAGE=es: {env_lang}")
|
|
44
|
+
|
|
45
|
+
# Test 3: Language fallback system
|
|
46
|
+
print("\n3. Testing language fallback system...")
|
|
47
|
+
supported = get_supported_languages()
|
|
48
|
+
print(f" Supported languages: {supported}")
|
|
49
|
+
|
|
50
|
+
test_languages = ['es', 'fr', 'de', 'zh-cn', 'pt-br', 'invalid-lang']
|
|
51
|
+
for lang in test_languages:
|
|
52
|
+
fallback = get_fallback_language(lang)
|
|
53
|
+
supported_check = is_language_supported(lang)
|
|
54
|
+
print(f" {lang} -> {fallback} (supported: {supported_check})")
|
|
55
|
+
|
|
56
|
+
# Test 4: Accept-Language header parsing
|
|
57
|
+
print("\n4. Testing Accept-Language header parsing...")
|
|
58
|
+
test_headers = [
|
|
59
|
+
'en-US,en;q=0.9,es;q=0.8,fr;q=0.7',
|
|
60
|
+
'es-ES,es;q=0.9,en;q=0.8',
|
|
61
|
+
'fr-FR,fr;q=0.9',
|
|
62
|
+
'de-DE,de;q=0.8,en;q=0.5',
|
|
63
|
+
'zh-CN,zh;q=0.9,en;q=0.1'
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
for header in test_headers:
|
|
67
|
+
parsed = _parse_accept_language_header(header)
|
|
68
|
+
print(f" '{header}' -> {parsed}")
|
|
69
|
+
|
|
70
|
+
# Test 5: Set language for request
|
|
71
|
+
print("\n5. Testing set_language_for_request...")
|
|
72
|
+
set_language_for_request('fr')
|
|
73
|
+
current_lang = get_current_language_from_request()
|
|
74
|
+
print(f" After setting to 'fr': {current_lang}")
|
|
75
|
+
|
|
76
|
+
# Reset for next tests
|
|
77
|
+
os.environ.pop('MINDROOT_LANGUAGE', None)
|
|
78
|
+
|
|
79
|
+
print("\n✅ Language detection tests completed!")
|
|
80
|
+
|
|
81
|
+
async def test_integrated_translation():
|
|
82
|
+
"""Test the integrated translation system with language detection."""
|
|
83
|
+
print("\nTesting Integrated Translation System...\n")
|
|
84
|
+
|
|
85
|
+
# Set up translations for multiple languages
|
|
86
|
+
print("1. Setting up translations...")
|
|
87
|
+
|
|
88
|
+
# English (default)
|
|
89
|
+
await set_translations('en', {
|
|
90
|
+
'welcome_title': 'Welcome to MindRoot',
|
|
91
|
+
'nav_home': 'Home',
|
|
92
|
+
'nav_settings': 'Settings',
|
|
93
|
+
'button_save': 'Save',
|
|
94
|
+
'button_cancel': 'Cancel'
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
# Spanish
|
|
98
|
+
await set_translations('es', {
|
|
99
|
+
'welcome_title': 'Bienvenido a MindRoot',
|
|
100
|
+
'nav_home': 'Inicio',
|
|
101
|
+
'nav_settings': 'Configuración',
|
|
102
|
+
'button_save': 'Guardar',
|
|
103
|
+
'button_cancel': 'Cancelar'
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
# French
|
|
107
|
+
await set_translations('fr', {
|
|
108
|
+
'welcome_title': 'Bienvenue à MindRoot',
|
|
109
|
+
'nav_home': 'Accueil',
|
|
110
|
+
'nav_settings': 'Paramètres',
|
|
111
|
+
'button_save': 'Enregistrer',
|
|
112
|
+
'button_cancel': 'Annuler'
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
# German
|
|
116
|
+
await set_translations('de', {
|
|
117
|
+
'welcome_title': 'Willkommen bei MindRoot',
|
|
118
|
+
'nav_home': 'Startseite',
|
|
119
|
+
'nav_settings': 'Einstellungen',
|
|
120
|
+
'button_save': 'Speichern',
|
|
121
|
+
'button_cancel': 'Abbrechen'
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
print(f" Set up translations for {len(TRANSLATIONS)} languages")
|
|
125
|
+
|
|
126
|
+
# Test template with placeholders
|
|
127
|
+
template_content = """
|
|
128
|
+
<html>
|
|
129
|
+
<head>
|
|
130
|
+
<title>__TRANSLATE_welcome_title__</title>
|
|
131
|
+
</head>
|
|
132
|
+
<body>
|
|
133
|
+
<nav>
|
|
134
|
+
<a href="/">__TRANSLATE_nav_home__</a>
|
|
135
|
+
<a href="/settings">__TRANSLATE_nav_settings__</a>
|
|
136
|
+
</nav>
|
|
137
|
+
<main>
|
|
138
|
+
<h1>__TRANSLATE_welcome_title__</h1>
|
|
139
|
+
<div class="actions">
|
|
140
|
+
<button>__TRANSLATE_button_save__</button>
|
|
141
|
+
<button>__TRANSLATE_button_cancel__</button>
|
|
142
|
+
</div>
|
|
143
|
+
</main>
|
|
144
|
+
</body>
|
|
145
|
+
</html>
|
|
146
|
+
""".strip()
|
|
147
|
+
|
|
148
|
+
# Test translation for each language
|
|
149
|
+
print("\n2. Testing translation for each language...")
|
|
150
|
+
|
|
151
|
+
test_languages = ['en', 'es', 'fr', 'de', 'pt'] # pt should fallback to en
|
|
152
|
+
|
|
153
|
+
for lang in test_languages:
|
|
154
|
+
print(f"\n Language: {lang}")
|
|
155
|
+
|
|
156
|
+
# Set the language
|
|
157
|
+
set_language_for_request(lang)
|
|
158
|
+
|
|
159
|
+
# Get the fallback language
|
|
160
|
+
fallback_lang = get_fallback_language(lang)
|
|
161
|
+
print(f" Fallback: {fallback_lang}")
|
|
162
|
+
|
|
163
|
+
# Translate the template
|
|
164
|
+
translated = replace_placeholders(template_content, fallback_lang)
|
|
165
|
+
|
|
166
|
+
# Show a snippet of the translation
|
|
167
|
+
title_line = [line for line in translated.split('\n') if '<title>' in line][0]
|
|
168
|
+
h1_line = [line for line in translated.split('\n') if '<h1>' in line][0]
|
|
169
|
+
|
|
170
|
+
print(f" Title: {title_line.strip()}")
|
|
171
|
+
print(f" H1: {h1_line.strip()}")
|
|
172
|
+
|
|
173
|
+
print("\n✅ Integrated translation tests completed!")
|
|
174
|
+
|
|
175
|
+
async def test_file_integration():
|
|
176
|
+
"""Test creating localized files and using language detection."""
|
|
177
|
+
print("\nTesting File Integration...\n")
|
|
178
|
+
|
|
179
|
+
# Create a localized template file
|
|
180
|
+
print("1. Creating localized template file...")
|
|
181
|
+
|
|
182
|
+
template_path = "/files/mindroot/src/mindroot/coreplugins/admin/templates/admin.jinja2"
|
|
183
|
+
template_content = """
|
|
184
|
+
<!DOCTYPE html>
|
|
185
|
+
<html>
|
|
186
|
+
<head>
|
|
187
|
+
<title>__TRANSLATE_admin_title__</title>
|
|
188
|
+
</head>
|
|
189
|
+
<body>
|
|
190
|
+
<header>
|
|
191
|
+
<h1>__TRANSLATE_admin_header__</h1>
|
|
192
|
+
<nav>
|
|
193
|
+
<a href="/admin/users">__TRANSLATE_nav_users__</a>
|
|
194
|
+
<a href="/admin/settings">__TRANSLATE_nav_settings__</a>
|
|
195
|
+
<a href="/admin/logs">__TRANSLATE_nav_logs__</a>
|
|
196
|
+
</nav>
|
|
197
|
+
</header>
|
|
198
|
+
<main>
|
|
199
|
+
<section>
|
|
200
|
+
<h2>__TRANSLATE_section_overview__</h2>
|
|
201
|
+
<p>__TRANSLATE_overview_description__</p>
|
|
202
|
+
</section>
|
|
203
|
+
<div class="actions">
|
|
204
|
+
<button class="primary">__TRANSLATE_button_create__</button>
|
|
205
|
+
<button class="secondary">__TRANSLATE_button_refresh__</button>
|
|
206
|
+
</div>
|
|
207
|
+
</main>
|
|
208
|
+
</body>
|
|
209
|
+
</html>
|
|
210
|
+
""".strip()
|
|
211
|
+
|
|
212
|
+
result = await write_localized_file(template_path, template_content)
|
|
213
|
+
print(f" {result}")
|
|
214
|
+
|
|
215
|
+
# Set up admin-specific translations
|
|
216
|
+
print("\n2. Setting up admin translations...")
|
|
217
|
+
|
|
218
|
+
admin_translations = {
|
|
219
|
+
'en': {
|
|
220
|
+
'admin_title': 'MindRoot Administration',
|
|
221
|
+
'admin_header': 'Admin Dashboard',
|
|
222
|
+
'nav_users': 'Users',
|
|
223
|
+
'nav_settings': 'Settings',
|
|
224
|
+
'nav_logs': 'Logs',
|
|
225
|
+
'section_overview': 'System Overview',
|
|
226
|
+
'overview_description': 'Manage your MindRoot installation from this dashboard.',
|
|
227
|
+
'button_create': 'Create New',
|
|
228
|
+
'button_refresh': 'Refresh Data'
|
|
229
|
+
},
|
|
230
|
+
'es': {
|
|
231
|
+
'admin_title': 'Administración de MindRoot',
|
|
232
|
+
'admin_header': 'Panel de Administración',
|
|
233
|
+
'nav_users': 'Usuarios',
|
|
234
|
+
'nav_settings': 'Configuración',
|
|
235
|
+
'nav_logs': 'Registros',
|
|
236
|
+
'section_overview': 'Resumen del Sistema',
|
|
237
|
+
'overview_description': 'Gestiona tu instalación de MindRoot desde este panel.',
|
|
238
|
+
'button_create': 'Crear Nuevo',
|
|
239
|
+
'button_refresh': 'Actualizar Datos'
|
|
240
|
+
},
|
|
241
|
+
'fr': {
|
|
242
|
+
'admin_title': 'Administration MindRoot',
|
|
243
|
+
'admin_header': 'Tableau de Bord Admin',
|
|
244
|
+
'nav_users': 'Utilisateurs',
|
|
245
|
+
'nav_settings': 'Paramètres',
|
|
246
|
+
'nav_logs': 'Journaux',
|
|
247
|
+
'section_overview': 'Aperçu du Système',
|
|
248
|
+
'overview_description': 'Gérez votre installation MindRoot depuis ce tableau de bord.',
|
|
249
|
+
'button_create': 'Créer Nouveau',
|
|
250
|
+
'button_refresh': 'Actualiser les Données'
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
for lang, translations in admin_translations.items():
|
|
255
|
+
result = await set_translations(lang, translations)
|
|
256
|
+
print(f" {result}")
|
|
257
|
+
|
|
258
|
+
# Test the complete workflow
|
|
259
|
+
print("\n3. Testing complete localization workflow...")
|
|
260
|
+
|
|
261
|
+
for lang in ['en', 'es', 'fr']:
|
|
262
|
+
print(f"\n Testing {lang.upper()} localization:")
|
|
263
|
+
|
|
264
|
+
# Set language
|
|
265
|
+
set_language_for_request(lang)
|
|
266
|
+
current = get_current_language_from_request()
|
|
267
|
+
fallback = get_fallback_language(current)
|
|
268
|
+
|
|
269
|
+
# Translate template
|
|
270
|
+
translated = replace_placeholders(template_content, fallback)
|
|
271
|
+
|
|
272
|
+
# Extract and show key elements
|
|
273
|
+
lines = translated.split('\n')
|
|
274
|
+
title = next((line for line in lines if '<title>' in line), '').strip()
|
|
275
|
+
header = next((line for line in lines if '<h1>' in line), '').strip()
|
|
276
|
+
|
|
277
|
+
print(f" Language: {current} -> Fallback: {fallback}")
|
|
278
|
+
print(f" {title}")
|
|
279
|
+
print(f" {header}")
|
|
280
|
+
|
|
281
|
+
print("\n✅ File integration tests completed!")
|
|
282
|
+
|
|
283
|
+
async def main():
|
|
284
|
+
"""Run all enhanced tests."""
|
|
285
|
+
print("=" * 60)
|
|
286
|
+
print("MindRoot l8n Plugin - Enhanced Testing Suite")
|
|
287
|
+
print("=" * 60)
|
|
288
|
+
|
|
289
|
+
await test_language_detection()
|
|
290
|
+
await test_integrated_translation()
|
|
291
|
+
await test_file_integration()
|
|
292
|
+
|
|
293
|
+
print("\n" + "=" * 60)
|
|
294
|
+
print("✅ All enhanced tests completed successfully!")
|
|
295
|
+
print("=" * 60)
|
|
296
|
+
|
|
297
|
+
if __name__ == "__main__":
|
|
298
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Simple test script for the l8n localization plugin.
|
|
4
|
+
|
|
5
|
+
This script tests the basic functionality of the localization commands
|
|
6
|
+
without requiring the full MindRoot environment.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import sys
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
# Add the current directory to Python path for imports
|
|
14
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
15
|
+
|
|
16
|
+
from mod import (
|
|
17
|
+
write_localized_file,
|
|
18
|
+
append_localized_file,
|
|
19
|
+
set_translations,
|
|
20
|
+
get_translations,
|
|
21
|
+
list_localized_files,
|
|
22
|
+
replace_placeholders
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
async def test_basic_functionality():
|
|
26
|
+
"""Test the basic l8n functionality."""
|
|
27
|
+
print("Testing MindRoot l8n Plugin...\n")
|
|
28
|
+
|
|
29
|
+
# Test 1: Create a localized file
|
|
30
|
+
print("1. Testing write_localized_file...")
|
|
31
|
+
test_path = "/files/mindroot/src/mindroot/coreplugins/chat/templates/chat.jinja2"
|
|
32
|
+
test_content = "<h1>__TRANSLATE_chat_title__</h1><button>__TRANSLATE_buttons_send__</button>"
|
|
33
|
+
|
|
34
|
+
result = await write_localized_file(test_path, test_content)
|
|
35
|
+
print(f" Result: {result}")
|
|
36
|
+
|
|
37
|
+
# Test 2: Append to the file
|
|
38
|
+
print("\n2. Testing append_localized_file...")
|
|
39
|
+
append_content = "<p>__TRANSLATE_welcome_message__</p>"
|
|
40
|
+
|
|
41
|
+
result = await append_localized_file(test_path, append_content)
|
|
42
|
+
print(f" Result: {result}")
|
|
43
|
+
|
|
44
|
+
# Test 3: Set translations
|
|
45
|
+
print("\n3. Testing set_translations...")
|
|
46
|
+
spanish_translations = {
|
|
47
|
+
'chat_title': 'Interfaz de Chat',
|
|
48
|
+
'buttons_send': 'Enviar Mensaje',
|
|
49
|
+
'welcome_message': 'Bienvenido al chat'
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
result = await set_translations('es', spanish_translations)
|
|
53
|
+
print(f" Result: {result}")
|
|
54
|
+
|
|
55
|
+
# Test 4: Set more translations
|
|
56
|
+
french_translations = {
|
|
57
|
+
'chat_title': 'Interface de Chat',
|
|
58
|
+
'buttons_send': 'Envoyer le Message',
|
|
59
|
+
'welcome_message': 'Bienvenue dans le chat'
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
result = await set_translations('fr', french_translations)
|
|
63
|
+
print(f" Result: {result}")
|
|
64
|
+
|
|
65
|
+
# Test 5: Get translations
|
|
66
|
+
print("\n4. Testing get_translations...")
|
|
67
|
+
es_translations = await get_translations('es')
|
|
68
|
+
print(f" Spanish translations: {es_translations}")
|
|
69
|
+
|
|
70
|
+
all_translations = await get_translations()
|
|
71
|
+
print(f" All languages: {list(all_translations.keys())}")
|
|
72
|
+
|
|
73
|
+
# Test 6: List localized files
|
|
74
|
+
print("\n5. Testing list_localized_files...")
|
|
75
|
+
files_result = await list_localized_files()
|
|
76
|
+
print(f" Result: {files_result}")
|
|
77
|
+
|
|
78
|
+
# Test 7: Test placeholder replacement
|
|
79
|
+
print("\n6. Testing placeholder replacement...")
|
|
80
|
+
test_template = "<h1>__TRANSLATE_chat_title__</h1><button>__TRANSLATE_buttons_send__</button><p>__TRANSLATE_welcome_message__</p>"
|
|
81
|
+
|
|
82
|
+
spanish_result = replace_placeholders(test_template, 'es')
|
|
83
|
+
print(f" Spanish: {spanish_result}")
|
|
84
|
+
|
|
85
|
+
french_result = replace_placeholders(test_template, 'fr')
|
|
86
|
+
print(f" French: {french_result}")
|
|
87
|
+
|
|
88
|
+
# Test 8: Test with unknown language (should return original)
|
|
89
|
+
unknown_result = replace_placeholders(test_template, 'de')
|
|
90
|
+
print(f" German (unknown): {unknown_result}")
|
|
91
|
+
|
|
92
|
+
print("\n✅ All tests completed!")
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
asyncio.run(test_basic_functionality())
|