mindroot 9.3.0__py3-none-any.whl → 9.6.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 +105 -9
- 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-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 +903 -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/indices/default/index.json +39 -6
- mindroot/coreplugins/jwt_auth/middleware.py +47 -2
- 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/router.py +2 -0
- 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 +236 -24
- 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 +39 -20
- mindroot/registry/data_access.py +1 -1
- mindroot/server.py +42 -13
- mindroot/server_missing_normal_args.py +197 -0
- mindroot/server_prev.py +173 -0
- {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/METADATA +7 -2
- {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/RECORD +143 -113
- mindroot/coreplugins/admin/plugin_manager_backup.py +0 -615
- 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 -12
- 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.3.0.dist-info → mindroot-9.6.0.dist-info}/WHEEL +0 -0
- {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/entry_points.txt +0 -0
- {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/licenses/LICENSE +0 -0
- {mindroot-9.3.0.dist-info → mindroot-9.6.0.dist-info}/top_level.txt +0 -0
|
@@ -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())
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Standalone test script for the l8n localization plugin.
|
|
4
|
+
|
|
5
|
+
This script tests the core functionality without MindRoot dependencies.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
# Simulate the command decorator for testing
|
|
14
|
+
def command():
|
|
15
|
+
def decorator(func):
|
|
16
|
+
return func
|
|
17
|
+
return decorator
|
|
18
|
+
|
|
19
|
+
# Copy the core functions from mod.py without MindRoot dependencies
|
|
20
|
+
TRANSLATIONS = {}
|
|
21
|
+
LOCALIZED_FILES_DIR = Path(__file__).parent / "localized_files"
|
|
22
|
+
|
|
23
|
+
def extract_plugin_root(absolute_path: str) -> str:
|
|
24
|
+
"""Extract the plugin root from an absolute path."""
|
|
25
|
+
path = Path(absolute_path)
|
|
26
|
+
parts = path.parts
|
|
27
|
+
|
|
28
|
+
# Find coreplugins in the path
|
|
29
|
+
if 'coreplugins' in parts:
|
|
30
|
+
coreplugins_idx = parts.index('coreplugins')
|
|
31
|
+
if coreplugins_idx + 1 < len(parts):
|
|
32
|
+
return '/'.join(parts[coreplugins_idx + 1:])
|
|
33
|
+
|
|
34
|
+
# Find src/[plugin_name] pattern for external plugins
|
|
35
|
+
for i, part in enumerate(parts):
|
|
36
|
+
if part == 'src' and i + 1 < len(parts):
|
|
37
|
+
potential_plugin = parts[i + 1]
|
|
38
|
+
if i + 2 < len(parts): # Has more path after src/plugin_name
|
|
39
|
+
return '/'.join(parts[i + 1:])
|
|
40
|
+
|
|
41
|
+
# Fallback: return the filename
|
|
42
|
+
return path.name
|
|
43
|
+
|
|
44
|
+
def get_localized_file_path(original_path: str) -> Path:
|
|
45
|
+
"""Convert an original file path to its localized version path."""
|
|
46
|
+
plugin_root = extract_plugin_root(original_path)
|
|
47
|
+
path = Path(plugin_root)
|
|
48
|
+
|
|
49
|
+
# Determine if this is a core plugin or external plugin
|
|
50
|
+
if any(core_plugin in plugin_root for core_plugin in ['chat', 'admin', 'l8n']):
|
|
51
|
+
# Core plugin
|
|
52
|
+
base_dir = LOCALIZED_FILES_DIR / "coreplugins"
|
|
53
|
+
else:
|
|
54
|
+
# External plugin
|
|
55
|
+
base_dir = LOCALIZED_FILES_DIR / "external_plugins"
|
|
56
|
+
|
|
57
|
+
# Add .i18n before the file extension
|
|
58
|
+
stem = path.stem
|
|
59
|
+
suffix = path.suffix
|
|
60
|
+
new_filename = f"{stem}.i18n{suffix}"
|
|
61
|
+
|
|
62
|
+
localized_path = base_dir / path.parent / new_filename
|
|
63
|
+
return localized_path
|
|
64
|
+
|
|
65
|
+
async def write_localized_file(original_path: str, content: str, context=None):
|
|
66
|
+
"""Write a localized version of a file with static placeholders."""
|
|
67
|
+
try:
|
|
68
|
+
localized_path = get_localized_file_path(original_path)
|
|
69
|
+
|
|
70
|
+
# Create directory if it doesn't exist
|
|
71
|
+
localized_path.parent.mkdir(parents=True, exist_ok=True)
|
|
72
|
+
|
|
73
|
+
# Write the content
|
|
74
|
+
with open(localized_path, 'w', encoding='utf-8') as f:
|
|
75
|
+
f.write(content)
|
|
76
|
+
|
|
77
|
+
return f"Localized file written to: {localized_path}"
|
|
78
|
+
|
|
79
|
+
except Exception as e:
|
|
80
|
+
return f"Error writing localized file: {str(e)}"
|
|
81
|
+
|
|
82
|
+
async def append_localized_file(original_path: str, content: str, context=None):
|
|
83
|
+
"""Append content to an existing localized file."""
|
|
84
|
+
try:
|
|
85
|
+
localized_path = get_localized_file_path(original_path)
|
|
86
|
+
|
|
87
|
+
# Create directory if it doesn't exist
|
|
88
|
+
localized_path.parent.mkdir(parents=True, exist_ok=True)
|
|
89
|
+
|
|
90
|
+
# Append the content
|
|
91
|
+
with open(localized_path, 'a', encoding='utf-8') as f:
|
|
92
|
+
f.write(content)
|
|
93
|
+
|
|
94
|
+
return f"Content appended to: {localized_path}"
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
return f"Error appending to localized file: {str(e)}"
|
|
98
|
+
|
|
99
|
+
async def set_translations(language: str, translations: dict, context=None):
|
|
100
|
+
"""Set translations for a specific language."""
|
|
101
|
+
try:
|
|
102
|
+
if not isinstance(translations, dict):
|
|
103
|
+
return "Error: translations must be a dictionary"
|
|
104
|
+
|
|
105
|
+
# Validate translation keys
|
|
106
|
+
invalid_keys = []
|
|
107
|
+
for key in translations.keys():
|
|
108
|
+
if not re.match(r'^[a-z0-9_]+$', key):
|
|
109
|
+
invalid_keys.append(key)
|
|
110
|
+
|
|
111
|
+
if invalid_keys:
|
|
112
|
+
return f"Error: Invalid translation keys: {invalid_keys}"
|
|
113
|
+
|
|
114
|
+
# Store translations
|
|
115
|
+
if language not in TRANSLATIONS:
|
|
116
|
+
TRANSLATIONS[language] = {}
|
|
117
|
+
|
|
118
|
+
TRANSLATIONS[language].update(translations)
|
|
119
|
+
|
|
120
|
+
return f"Set {len(translations)} translations for language '{language}'. Total languages: {len(TRANSLATIONS)}"
|
|
121
|
+
|
|
122
|
+
except Exception as e:
|
|
123
|
+
return f"Error setting translations: {str(e)}"
|
|
124
|
+
|
|
125
|
+
async def get_translations(language: str = None, context=None):
|
|
126
|
+
"""Get translations for a specific language or all languages."""
|
|
127
|
+
try:
|
|
128
|
+
if language:
|
|
129
|
+
return TRANSLATIONS.get(language, {})
|
|
130
|
+
else:
|
|
131
|
+
return TRANSLATIONS
|
|
132
|
+
|
|
133
|
+
except Exception as e:
|
|
134
|
+
return f"Error getting translations: {str(e)}"
|
|
135
|
+
|
|
136
|
+
async def list_localized_files(context=None):
|
|
137
|
+
"""List all localized files that have been created."""
|
|
138
|
+
try:
|
|
139
|
+
localized_files = []
|
|
140
|
+
|
|
141
|
+
if LOCALIZED_FILES_DIR.exists():
|
|
142
|
+
for file_path in LOCALIZED_FILES_DIR.rglob("*.i18n.*"):
|
|
143
|
+
localized_files.append(str(file_path.relative_to(LOCALIZED_FILES_DIR)))
|
|
144
|
+
|
|
145
|
+
return {
|
|
146
|
+
"count": len(localized_files),
|
|
147
|
+
"files": sorted(localized_files)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
except Exception as e:
|
|
151
|
+
return f"Error listing localized files: {str(e)}"
|
|
152
|
+
|
|
153
|
+
def replace_placeholders(content: str, language: str) -> str:
|
|
154
|
+
"""Replace __TRANSLATE_key__ placeholders with actual translations."""
|
|
155
|
+
if language not in TRANSLATIONS:
|
|
156
|
+
return content
|
|
157
|
+
|
|
158
|
+
translations = TRANSLATIONS[language]
|
|
159
|
+
|
|
160
|
+
def replace_match(match):
|
|
161
|
+
key = match.group(1)
|
|
162
|
+
return translations.get(key, match.group(0)) # Return original if no translation
|
|
163
|
+
|
|
164
|
+
# Replace all __TRANSLATE_key__ patterns
|
|
165
|
+
return re.sub(r'__TRANSLATE_([a-z0-9_]+)__', replace_match, content)
|
|
166
|
+
|
|
167
|
+
async def test_basic_functionality():
|
|
168
|
+
"""Test the basic l8n functionality."""
|
|
169
|
+
print("Testing MindRoot l8n Plugin (Standalone)...\n")
|
|
170
|
+
|
|
171
|
+
# Test 1: Create a localized file
|
|
172
|
+
print("1. Testing write_localized_file...")
|
|
173
|
+
test_path = "/files/mindroot/src/mindroot/coreplugins/chat/templates/chat.jinja2"
|
|
174
|
+
test_content = "<h1>__TRANSLATE_chat_title__</h1><button>__TRANSLATE_buttons_send__</button>"
|
|
175
|
+
|
|
176
|
+
result = await write_localized_file(test_path, test_content)
|
|
177
|
+
print(f" Result: {result}")
|
|
178
|
+
|
|
179
|
+
# Test 2: Append to the file
|
|
180
|
+
print("\n2. Testing append_localized_file...")
|
|
181
|
+
append_content = "<p>__TRANSLATE_welcome_message__</p>"
|
|
182
|
+
|
|
183
|
+
result = await append_localized_file(test_path, append_content)
|
|
184
|
+
print(f" Result: {result}")
|
|
185
|
+
|
|
186
|
+
# Test 3: Set translations
|
|
187
|
+
print("\n3. Testing set_translations...")
|
|
188
|
+
spanish_translations = {
|
|
189
|
+
'chat_title': 'Interfaz de Chat',
|
|
190
|
+
'buttons_send': 'Enviar Mensaje',
|
|
191
|
+
'welcome_message': 'Bienvenido al chat'
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
result = await set_translations('es', spanish_translations)
|
|
195
|
+
print(f" Result: {result}")
|
|
196
|
+
|
|
197
|
+
# Test 4: Set more translations
|
|
198
|
+
french_translations = {
|
|
199
|
+
'chat_title': 'Interface de Chat',
|
|
200
|
+
'buttons_send': 'Envoyer le Message',
|
|
201
|
+
'welcome_message': 'Bienvenue dans le chat'
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
result = await set_translations('fr', french_translations)
|
|
205
|
+
print(f" Result: {result}")
|
|
206
|
+
|
|
207
|
+
# Test 5: Get translations
|
|
208
|
+
print("\n4. Testing get_translations...")
|
|
209
|
+
es_translations = await get_translations('es')
|
|
210
|
+
print(f" Spanish translations: {es_translations}")
|
|
211
|
+
|
|
212
|
+
all_translations = await get_translations()
|
|
213
|
+
print(f" All languages: {list(all_translations.keys())}")
|
|
214
|
+
|
|
215
|
+
# Test 6: List localized files
|
|
216
|
+
print("\n5. Testing list_localized_files...")
|
|
217
|
+
files_result = await list_localized_files()
|
|
218
|
+
print(f" Result: {files_result}")
|
|
219
|
+
|
|
220
|
+
# Test 7: Test placeholder replacement
|
|
221
|
+
print("\n6. Testing placeholder replacement...")
|
|
222
|
+
test_template = "<h1>__TRANSLATE_chat_title__</h1><button>__TRANSLATE_buttons_send__</button><p>__TRANSLATE_welcome_message__</p>"
|
|
223
|
+
|
|
224
|
+
spanish_result = replace_placeholders(test_template, 'es')
|
|
225
|
+
print(f" Spanish: {spanish_result}")
|
|
226
|
+
|
|
227
|
+
french_result = replace_placeholders(test_template, 'fr')
|
|
228
|
+
print(f" French: {french_result}")
|
|
229
|
+
|
|
230
|
+
# Test 8: Test with unknown language (should return original)
|
|
231
|
+
unknown_result = replace_placeholders(test_template, 'de')
|
|
232
|
+
print(f" German (unknown): {unknown_result}")
|
|
233
|
+
|
|
234
|
+
# Test 9: Check created file content
|
|
235
|
+
print("\n7. Checking created file content...")
|
|
236
|
+
localized_path = get_localized_file_path(test_path)
|
|
237
|
+
if localized_path.exists():
|
|
238
|
+
with open(localized_path, 'r', encoding='utf-8') as f:
|
|
239
|
+
file_content = f.read()
|
|
240
|
+
print(f" File content: {repr(file_content)}")
|
|
241
|
+
|
|
242
|
+
# Test replacement on actual file content
|
|
243
|
+
spanish_file_result = replace_placeholders(file_content, 'es')
|
|
244
|
+
print(f" Spanish version: {spanish_file_result}")
|
|
245
|
+
else:
|
|
246
|
+
print(f" File not found: {localized_path}")
|
|
247
|
+
|
|
248
|
+
print("\n✅ All tests completed!")
|
|
249
|
+
|
|
250
|
+
if __name__ == "__main__":
|
|
251
|
+
asyncio.run(test_basic_functionality())
|