supervertaler 1.9.153__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.
Potentially problematic release.
This version of supervertaler might be problematic. Click here for more details.
- Supervertaler.py +47886 -0
- modules/__init__.py +10 -0
- modules/ai_actions.py +964 -0
- modules/ai_attachment_manager.py +343 -0
- modules/ai_file_viewer_dialog.py +210 -0
- modules/autofingers_engine.py +466 -0
- modules/cafetran_docx_handler.py +379 -0
- modules/config_manager.py +469 -0
- modules/database_manager.py +1878 -0
- modules/database_migrations.py +417 -0
- modules/dejavurtf_handler.py +779 -0
- modules/document_analyzer.py +427 -0
- modules/docx_handler.py +689 -0
- modules/encoding_repair.py +319 -0
- modules/encoding_repair_Qt.py +393 -0
- modules/encoding_repair_ui.py +481 -0
- modules/feature_manager.py +350 -0
- modules/figure_context_manager.py +340 -0
- modules/file_dialog_helper.py +148 -0
- modules/find_replace.py +164 -0
- modules/find_replace_qt.py +457 -0
- modules/glossary_manager.py +433 -0
- modules/image_extractor.py +188 -0
- modules/keyboard_shortcuts_widget.py +571 -0
- modules/llm_clients.py +1211 -0
- modules/llm_leaderboard.py +737 -0
- modules/llm_superbench_ui.py +1401 -0
- modules/local_llm_setup.py +1104 -0
- modules/model_update_dialog.py +381 -0
- modules/model_version_checker.py +373 -0
- modules/mqxliff_handler.py +638 -0
- modules/non_translatables_manager.py +743 -0
- modules/pdf_rescue_Qt.py +1822 -0
- modules/pdf_rescue_tkinter.py +909 -0
- modules/phrase_docx_handler.py +516 -0
- modules/project_home_panel.py +209 -0
- modules/prompt_assistant.py +357 -0
- modules/prompt_library.py +689 -0
- modules/prompt_library_migration.py +447 -0
- modules/quick_access_sidebar.py +282 -0
- modules/ribbon_widget.py +597 -0
- modules/sdlppx_handler.py +874 -0
- modules/setup_wizard.py +353 -0
- modules/shortcut_manager.py +932 -0
- modules/simple_segmenter.py +128 -0
- modules/spellcheck_manager.py +727 -0
- modules/statuses.py +207 -0
- modules/style_guide_manager.py +315 -0
- modules/superbench_ui.py +1319 -0
- modules/superbrowser.py +329 -0
- modules/supercleaner.py +600 -0
- modules/supercleaner_ui.py +444 -0
- modules/superdocs.py +19 -0
- modules/superdocs_viewer_qt.py +382 -0
- modules/superlookup.py +252 -0
- modules/tag_cleaner.py +260 -0
- modules/tag_manager.py +333 -0
- modules/term_extractor.py +270 -0
- modules/termbase_entry_editor.py +842 -0
- modules/termbase_import_export.py +488 -0
- modules/termbase_manager.py +1060 -0
- modules/termview_widget.py +1172 -0
- modules/theme_manager.py +499 -0
- modules/tm_editor_dialog.py +99 -0
- modules/tm_manager_qt.py +1280 -0
- modules/tm_metadata_manager.py +545 -0
- modules/tmx_editor.py +1461 -0
- modules/tmx_editor_qt.py +2784 -0
- modules/tmx_generator.py +284 -0
- modules/tracked_changes.py +900 -0
- modules/trados_docx_handler.py +430 -0
- modules/translation_memory.py +715 -0
- modules/translation_results_panel.py +2134 -0
- modules/translation_services.py +282 -0
- modules/unified_prompt_library.py +659 -0
- modules/unified_prompt_manager_qt.py +3951 -0
- modules/voice_commands.py +920 -0
- modules/voice_dictation.py +477 -0
- modules/voice_dictation_lite.py +249 -0
- supervertaler-1.9.153.dist-info/METADATA +896 -0
- supervertaler-1.9.153.dist-info/RECORD +85 -0
- supervertaler-1.9.153.dist-info/WHEEL +5 -0
- supervertaler-1.9.153.dist-info/entry_points.txt +2 -0
- supervertaler-1.9.153.dist-info/licenses/LICENSE +21 -0
- supervertaler-1.9.153.dist-info/top_level.txt +2 -0
modules/statuses.py
ADDED
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Centralized status vocabulary for Supervertaler segments."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Dict, Optional
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class StatusDefinition:
|
|
10
|
+
key: str
|
|
11
|
+
label: str
|
|
12
|
+
icon: str
|
|
13
|
+
color: str
|
|
14
|
+
memoq_label: str
|
|
15
|
+
memoQ_equivalents: tuple[str, ...]
|
|
16
|
+
match_symbol: str = ""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
STATUSES: Dict[str, StatusDefinition] = {
|
|
20
|
+
"not_started": StatusDefinition(
|
|
21
|
+
key="not_started",
|
|
22
|
+
label="Not started",
|
|
23
|
+
icon="❌", # Red X - clear "not done" indicator (matches memoQ style)
|
|
24
|
+
color="#ffe6e6",
|
|
25
|
+
memoq_label="Not started",
|
|
26
|
+
memoQ_equivalents=("not started", "not translated"),
|
|
27
|
+
),
|
|
28
|
+
"pretranslated": StatusDefinition(
|
|
29
|
+
key="pretranslated",
|
|
30
|
+
label="Pre-translated",
|
|
31
|
+
icon="🤖", # Robot - indicates automatic/machine pre-translation
|
|
32
|
+
color="#e8f2ff",
|
|
33
|
+
memoq_label="Pre-translated",
|
|
34
|
+
memoQ_equivalents=("pre-translated", "pretranslated"),
|
|
35
|
+
match_symbol="⚡",
|
|
36
|
+
),
|
|
37
|
+
"translated": StatusDefinition(
|
|
38
|
+
key="translated",
|
|
39
|
+
label="Translated",
|
|
40
|
+
icon="✏️", # Pencil - indicates manual translation work (matches Trados style)
|
|
41
|
+
color="#e6ffe6",
|
|
42
|
+
memoq_label="Translated",
|
|
43
|
+
memoQ_equivalents=("translated",),
|
|
44
|
+
match_symbol="✍️",
|
|
45
|
+
),
|
|
46
|
+
"confirmed": StatusDefinition(
|
|
47
|
+
key="confirmed",
|
|
48
|
+
label="Confirmed",
|
|
49
|
+
icon="✔", # Checkmark - will be styled green via CSS
|
|
50
|
+
color="#d1ffd6",
|
|
51
|
+
memoq_label="Confirmed",
|
|
52
|
+
memoQ_equivalents=("confirmed",),
|
|
53
|
+
match_symbol="🛡️",
|
|
54
|
+
),
|
|
55
|
+
"tr_confirmed": StatusDefinition(
|
|
56
|
+
key="tr_confirmed",
|
|
57
|
+
label="TR confirmed",
|
|
58
|
+
icon="🌟",
|
|
59
|
+
color="#d9f0ff",
|
|
60
|
+
memoq_label="TR confirmed",
|
|
61
|
+
memoQ_equivalents=("tr confirmed", "translation review confirmed"),
|
|
62
|
+
match_symbol="🌐",
|
|
63
|
+
),
|
|
64
|
+
"proofread": StatusDefinition(
|
|
65
|
+
key="proofread",
|
|
66
|
+
label="Proofread",
|
|
67
|
+
icon="🟪",
|
|
68
|
+
color="#efe0ff",
|
|
69
|
+
memoq_label="Proofread",
|
|
70
|
+
memoQ_equivalents=("proofread",),
|
|
71
|
+
match_symbol="📘",
|
|
72
|
+
),
|
|
73
|
+
"rejected": StatusDefinition(
|
|
74
|
+
key="rejected",
|
|
75
|
+
label="Rejected",
|
|
76
|
+
icon="🚫",
|
|
77
|
+
color="#ffe0e0",
|
|
78
|
+
memoq_label="Rejected",
|
|
79
|
+
memoQ_equivalents=("rejected",),
|
|
80
|
+
match_symbol="⛔",
|
|
81
|
+
),
|
|
82
|
+
"approved": StatusDefinition(
|
|
83
|
+
key="approved",
|
|
84
|
+
label="Approved",
|
|
85
|
+
icon="⭐",
|
|
86
|
+
color="#e6f3ff",
|
|
87
|
+
memoq_label="Approved",
|
|
88
|
+
memoQ_equivalents=("approved", "final", "proofread confirmed"),
|
|
89
|
+
match_symbol="🏁",
|
|
90
|
+
),
|
|
91
|
+
"pm": StatusDefinition(
|
|
92
|
+
key="pm",
|
|
93
|
+
label="PM (102%)",
|
|
94
|
+
icon="⭐", # Star - perfect/double context match
|
|
95
|
+
color="#b8daff", # Light blue - highest confidence
|
|
96
|
+
memoq_label="Pre-translated (102%)",
|
|
97
|
+
memoQ_equivalents=("pre-translated (102%)", "102%", "xlt", "double context", "perfect match", "pm"),
|
|
98
|
+
match_symbol="⭐",
|
|
99
|
+
),
|
|
100
|
+
"cm": StatusDefinition(
|
|
101
|
+
key="cm",
|
|
102
|
+
label="CM (101%)",
|
|
103
|
+
icon="💎", # Diamond - context match
|
|
104
|
+
color="#c3e6cb", # Darker green - very high confidence
|
|
105
|
+
memoq_label="Pre-translated (101%)",
|
|
106
|
+
memoQ_equivalents=("pre-translated (101%)", "context match", "cm", "101%"),
|
|
107
|
+
match_symbol="💎",
|
|
108
|
+
),
|
|
109
|
+
"tm_100": StatusDefinition(
|
|
110
|
+
key="tm_100",
|
|
111
|
+
label="TM 100%",
|
|
112
|
+
icon="✅", # Checkmark - exact match
|
|
113
|
+
color="#d4edda", # Light green - high confidence
|
|
114
|
+
memoq_label="Pre-translated (100%)",
|
|
115
|
+
memoQ_equivalents=("pre-translated (100%)", "100%", "exact match"),
|
|
116
|
+
match_symbol="✅",
|
|
117
|
+
),
|
|
118
|
+
"tm_fuzzy": StatusDefinition(
|
|
119
|
+
key="tm_fuzzy",
|
|
120
|
+
label="TM Fuzzy",
|
|
121
|
+
icon="🔶", # Orange diamond - partial match
|
|
122
|
+
color="#fff3cd", # Light yellow/orange - needs review
|
|
123
|
+
memoq_label="Pre-translated (fuzzy)",
|
|
124
|
+
memoQ_equivalents=("fuzzy", "fuzzy match"),
|
|
125
|
+
match_symbol="🔶",
|
|
126
|
+
),
|
|
127
|
+
"repetition": StatusDefinition(
|
|
128
|
+
key="repetition",
|
|
129
|
+
label="Repetition",
|
|
130
|
+
icon="🔁", # Repeat icon - internal repetition
|
|
131
|
+
color="#e2e3e5", # Light gray - auto-propagated
|
|
132
|
+
memoq_label="Repetition",
|
|
133
|
+
memoQ_equivalents=("repetition", "rep", "auto-propagated"),
|
|
134
|
+
match_symbol="🔁",
|
|
135
|
+
),
|
|
136
|
+
"machine_translated": StatusDefinition(
|
|
137
|
+
key="machine_translated",
|
|
138
|
+
label="MT",
|
|
139
|
+
icon="🤖", # Robot - machine translation
|
|
140
|
+
color="#ffeaa7", # Light orange/yellow - needs review
|
|
141
|
+
memoq_label="Machine Translated",
|
|
142
|
+
memoQ_equivalents=("machine translated", "mt", "nmt", "auto-translated"),
|
|
143
|
+
match_symbol="🤖",
|
|
144
|
+
),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
DEFAULT_STATUS = STATUSES["not_started"]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_status(key: str) -> StatusDefinition:
|
|
151
|
+
"""Return status definition for key, falling back to default."""
|
|
152
|
+
return STATUSES.get(key, DEFAULT_STATUS)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def match_memoq_status(status_text: str) -> tuple[StatusDefinition, Optional[int]]:
|
|
156
|
+
"""Map memoQ status string to a StatusDefinition plus optional match percent."""
|
|
157
|
+
status_clean = (status_text or "").strip()
|
|
158
|
+
percent: Optional[int] = None
|
|
159
|
+
|
|
160
|
+
if status_clean:
|
|
161
|
+
match = re.search(r"(\d+)\s*%", status_clean)
|
|
162
|
+
if match:
|
|
163
|
+
try:
|
|
164
|
+
percent = int(match.group(1))
|
|
165
|
+
except ValueError:
|
|
166
|
+
percent = None
|
|
167
|
+
|
|
168
|
+
lower = status_clean.lower()
|
|
169
|
+
|
|
170
|
+
for definition in STATUSES.values():
|
|
171
|
+
if any(eq in lower for eq in definition.memoQ_equivalents):
|
|
172
|
+
return definition, percent
|
|
173
|
+
|
|
174
|
+
if "proofread" in lower and "confirm" in lower:
|
|
175
|
+
return STATUSES["approved"], percent
|
|
176
|
+
if "confirm" in lower and "tr" in lower:
|
|
177
|
+
return STATUSES["tr_confirmed"], percent
|
|
178
|
+
if "confirm" in lower:
|
|
179
|
+
return STATUSES["confirmed"], percent
|
|
180
|
+
if "lock" in lower:
|
|
181
|
+
return STATUSES["not_started"], percent
|
|
182
|
+
if "reject" in lower:
|
|
183
|
+
return STATUSES["rejected"], percent
|
|
184
|
+
if "proof" in lower:
|
|
185
|
+
return STATUSES["proofread"], percent
|
|
186
|
+
if "translate" in lower:
|
|
187
|
+
return STATUSES["translated"], percent
|
|
188
|
+
|
|
189
|
+
return DEFAULT_STATUS, percent
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def compose_memoq_status(
|
|
193
|
+
status_key: str,
|
|
194
|
+
match_percent: Optional[int] = None,
|
|
195
|
+
existing: Optional[str] = None,
|
|
196
|
+
) -> str:
|
|
197
|
+
"""Compose a memoQ status string, preserving existing text when provided."""
|
|
198
|
+
if existing and existing.strip():
|
|
199
|
+
return existing.strip()
|
|
200
|
+
|
|
201
|
+
status_def = get_status(status_key)
|
|
202
|
+
base = status_def.memoq_label
|
|
203
|
+
if match_percent is not None:
|
|
204
|
+
return f"{base} ({match_percent}%)"
|
|
205
|
+
return base
|
|
206
|
+
|
|
207
|
+
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Style Guide Manager Module
|
|
3
|
+
|
|
4
|
+
Manages translation style guides for different languages.
|
|
5
|
+
Supports style guides as Markdown files with optional YAML frontmatter.
|
|
6
|
+
|
|
7
|
+
Extracted for modularity and reusability.
|
|
8
|
+
Supports both individual language-specific guides and optional user additions.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import json
|
|
13
|
+
import shutil
|
|
14
|
+
import re
|
|
15
|
+
from datetime import datetime
|
|
16
|
+
from typing import Dict, List, Optional, Tuple
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class StyleGuideLibrary:
|
|
20
|
+
"""
|
|
21
|
+
Manages translation style guides for multiple languages.
|
|
22
|
+
Loads style guide files from appropriate folder based on dev mode.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# Supported languages for style guides
|
|
26
|
+
SUPPORTED_LANGUAGES = [
|
|
27
|
+
"Dutch",
|
|
28
|
+
"English",
|
|
29
|
+
"Spanish",
|
|
30
|
+
"German",
|
|
31
|
+
"French"
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
def __init__(self, style_guides_dir=None, log_callback=None):
|
|
35
|
+
"""
|
|
36
|
+
Initialize the Style Guide Library.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
style_guides_dir: Path to style guides directory (if None, must be set later)
|
|
40
|
+
log_callback: Function to call for logging messages
|
|
41
|
+
"""
|
|
42
|
+
self.style_guides_dir = style_guides_dir
|
|
43
|
+
self.log = log_callback if log_callback else print
|
|
44
|
+
|
|
45
|
+
# Create directory if it doesn't exist and path is provided
|
|
46
|
+
if self.style_guides_dir:
|
|
47
|
+
os.makedirs(self.style_guides_dir, exist_ok=True)
|
|
48
|
+
|
|
49
|
+
# Available style guides: {language: guide_data}
|
|
50
|
+
self.guides = {}
|
|
51
|
+
self.active_guide = None # Currently selected guide
|
|
52
|
+
self.active_guide_language = None
|
|
53
|
+
|
|
54
|
+
def set_directory(self, style_guides_dir):
|
|
55
|
+
"""Set the directory after initialization"""
|
|
56
|
+
self.style_guides_dir = style_guides_dir
|
|
57
|
+
os.makedirs(self.style_guides_dir, exist_ok=True)
|
|
58
|
+
|
|
59
|
+
def load_all_guides(self):
|
|
60
|
+
"""Load all style guides from the style guides directory"""
|
|
61
|
+
self.guides = {}
|
|
62
|
+
|
|
63
|
+
if not self.style_guides_dir or not os.path.exists(self.style_guides_dir):
|
|
64
|
+
self.log("⚠ Style guides directory not found")
|
|
65
|
+
return 0
|
|
66
|
+
|
|
67
|
+
count = self._load_from_directory(self.style_guides_dir)
|
|
68
|
+
self.log(f"✓ Loaded {count} style guides")
|
|
69
|
+
return count
|
|
70
|
+
|
|
71
|
+
def _load_from_directory(self, directory):
|
|
72
|
+
"""Load style guides from directory
|
|
73
|
+
|
|
74
|
+
Expected file naming: <Language>.md or <Language>.txt
|
|
75
|
+
Examples: Dutch.md, English.md, Spanish.txt, etc.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
directory: Path to directory
|
|
79
|
+
"""
|
|
80
|
+
count = 0
|
|
81
|
+
|
|
82
|
+
if not directory or not os.path.exists(directory):
|
|
83
|
+
return count
|
|
84
|
+
|
|
85
|
+
for filename in os.listdir(directory):
|
|
86
|
+
filepath = os.path.join(directory, filename)
|
|
87
|
+
|
|
88
|
+
# Skip directories
|
|
89
|
+
if os.path.isdir(filepath):
|
|
90
|
+
continue
|
|
91
|
+
|
|
92
|
+
# Check if file matches supported language format
|
|
93
|
+
if filename.endswith('.md') or filename.endswith('.txt'):
|
|
94
|
+
language = filename.rsplit('.', 1)[0] # Remove extension
|
|
95
|
+
|
|
96
|
+
# Load content
|
|
97
|
+
try:
|
|
98
|
+
with open(filepath, 'r', encoding='utf-8') as f:
|
|
99
|
+
content = f.read()
|
|
100
|
+
|
|
101
|
+
guide_data = {
|
|
102
|
+
'language': language,
|
|
103
|
+
'content': content,
|
|
104
|
+
'_filename': filename,
|
|
105
|
+
'_filepath': filepath,
|
|
106
|
+
'_created': datetime.fromtimestamp(os.path.getctime(filepath)).isoformat(),
|
|
107
|
+
'_modified': datetime.fromtimestamp(os.path.getmtime(filepath)).isoformat(),
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
self.guides[language] = guide_data
|
|
111
|
+
count += 1
|
|
112
|
+
|
|
113
|
+
except Exception as e:
|
|
114
|
+
self.log(f"⚠ Failed to load {filename}: {e}")
|
|
115
|
+
|
|
116
|
+
return count
|
|
117
|
+
|
|
118
|
+
def get_guide(self, language: str) -> Optional[Dict]:
|
|
119
|
+
"""
|
|
120
|
+
Get a specific style guide by language.
|
|
121
|
+
|
|
122
|
+
Args:
|
|
123
|
+
language: Language name (e.g., 'Dutch', 'English')
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
Dictionary with guide data or None if not found
|
|
127
|
+
"""
|
|
128
|
+
return self.guides.get(language)
|
|
129
|
+
|
|
130
|
+
def get_all_languages(self) -> List[str]:
|
|
131
|
+
"""Get list of all available style guide languages"""
|
|
132
|
+
return sorted(self.guides.keys())
|
|
133
|
+
|
|
134
|
+
def get_guide_content(self, language: str) -> Optional[str]:
|
|
135
|
+
"""Get the content of a specific style guide"""
|
|
136
|
+
guide = self.guides.get(language)
|
|
137
|
+
return guide['content'] if guide else None
|
|
138
|
+
|
|
139
|
+
def update_guide(self, language: str, new_content: str) -> bool:
|
|
140
|
+
"""
|
|
141
|
+
Update a style guide with new content.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
language: Language name
|
|
145
|
+
new_content: New content for the guide
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
True if successful, False otherwise
|
|
149
|
+
"""
|
|
150
|
+
guide = self.guides.get(language)
|
|
151
|
+
if not guide:
|
|
152
|
+
self.log(f"⚠ Style guide not found: {language}")
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
filepath = guide['_filepath']
|
|
157
|
+
|
|
158
|
+
# Write to file
|
|
159
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
160
|
+
f.write(new_content)
|
|
161
|
+
|
|
162
|
+
# Update in memory
|
|
163
|
+
guide['content'] = new_content
|
|
164
|
+
guide['_modified'] = datetime.now().isoformat()
|
|
165
|
+
|
|
166
|
+
self.log(f"✓ Updated style guide: {language}")
|
|
167
|
+
return True
|
|
168
|
+
|
|
169
|
+
except Exception as e:
|
|
170
|
+
self.log(f"⚠ Failed to update {language}: {e}")
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
def append_to_guide(self, language: str, additional_content: str) -> bool:
|
|
174
|
+
"""
|
|
175
|
+
Append content to an existing style guide.
|
|
176
|
+
|
|
177
|
+
Args:
|
|
178
|
+
language: Language name
|
|
179
|
+
additional_content: Content to append
|
|
180
|
+
|
|
181
|
+
Returns:
|
|
182
|
+
True if successful, False otherwise
|
|
183
|
+
"""
|
|
184
|
+
guide = self.guides.get(language)
|
|
185
|
+
if not guide:
|
|
186
|
+
self.log(f"⚠ Style guide not found: {language}")
|
|
187
|
+
return False
|
|
188
|
+
|
|
189
|
+
current_content = guide['content']
|
|
190
|
+
new_content = current_content.rstrip() + '\n\n' + additional_content.strip()
|
|
191
|
+
|
|
192
|
+
return self.update_guide(language, new_content)
|
|
193
|
+
|
|
194
|
+
def append_to_all_guides(self, additional_content: str) -> Tuple[int, int]:
|
|
195
|
+
"""
|
|
196
|
+
Append content to all style guides.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
additional_content: Content to append to all guides
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
Tuple of (successful_count, failed_count)
|
|
203
|
+
"""
|
|
204
|
+
successful = 0
|
|
205
|
+
failed = 0
|
|
206
|
+
|
|
207
|
+
for language in self.guides.keys():
|
|
208
|
+
if self.append_to_guide(language, additional_content):
|
|
209
|
+
successful += 1
|
|
210
|
+
else:
|
|
211
|
+
failed += 1
|
|
212
|
+
|
|
213
|
+
self.log(f"✓ Updated {successful} guides. Failed: {failed}")
|
|
214
|
+
return successful, failed
|
|
215
|
+
|
|
216
|
+
def create_guide(self, language: str, content: str = "") -> bool:
|
|
217
|
+
"""
|
|
218
|
+
Create a new style guide file.
|
|
219
|
+
|
|
220
|
+
Args:
|
|
221
|
+
language: Language name
|
|
222
|
+
content: Initial content (optional)
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
True if successful, False otherwise
|
|
226
|
+
"""
|
|
227
|
+
if not self.style_guides_dir:
|
|
228
|
+
self.log("⚠ Style guides directory not set")
|
|
229
|
+
return False
|
|
230
|
+
|
|
231
|
+
if language in self.guides:
|
|
232
|
+
self.log(f"⚠ Style guide already exists: {language}")
|
|
233
|
+
return False
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
filepath = os.path.join(self.style_guides_dir, f"{language}.md")
|
|
237
|
+
|
|
238
|
+
# Create file
|
|
239
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
|
240
|
+
f.write(content)
|
|
241
|
+
|
|
242
|
+
# Add to guides dictionary
|
|
243
|
+
guide_data = {
|
|
244
|
+
'language': language,
|
|
245
|
+
'content': content,
|
|
246
|
+
'_filename': f"{language}.md",
|
|
247
|
+
'_filepath': filepath,
|
|
248
|
+
'_created': datetime.now().isoformat(),
|
|
249
|
+
'_modified': datetime.now().isoformat(),
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
self.guides[language] = guide_data
|
|
253
|
+
self.log(f"✓ Created style guide: {language}")
|
|
254
|
+
return True
|
|
255
|
+
|
|
256
|
+
except Exception as e:
|
|
257
|
+
self.log(f"⚠ Failed to create {language}: {e}")
|
|
258
|
+
return False
|
|
259
|
+
|
|
260
|
+
def export_guide(self, language: str, export_path: str) -> bool:
|
|
261
|
+
"""
|
|
262
|
+
Export a style guide to a file.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
language: Language name
|
|
266
|
+
export_path: Path where to save the exported guide
|
|
267
|
+
|
|
268
|
+
Returns:
|
|
269
|
+
True if successful, False otherwise
|
|
270
|
+
"""
|
|
271
|
+
guide = self.guides.get(language)
|
|
272
|
+
if not guide:
|
|
273
|
+
self.log(f"⚠ Style guide not found: {language}")
|
|
274
|
+
return False
|
|
275
|
+
|
|
276
|
+
try:
|
|
277
|
+
with open(export_path, 'w', encoding='utf-8') as f:
|
|
278
|
+
f.write(guide['content'])
|
|
279
|
+
|
|
280
|
+
self.log(f"✓ Exported style guide: {language}")
|
|
281
|
+
return True
|
|
282
|
+
|
|
283
|
+
except Exception as e:
|
|
284
|
+
self.log(f"⚠ Failed to export {language}: {e}")
|
|
285
|
+
return False
|
|
286
|
+
|
|
287
|
+
def import_guide(self, language: str, import_path: str, append: bool = False) -> bool:
|
|
288
|
+
"""
|
|
289
|
+
Import a style guide from a file.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
language: Language name to import as
|
|
293
|
+
import_path: Path to the file to import
|
|
294
|
+
append: If True, append to existing guide; if False, replace
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
True if successful, False otherwise
|
|
298
|
+
"""
|
|
299
|
+
try:
|
|
300
|
+
with open(import_path, 'r', encoding='utf-8') as f:
|
|
301
|
+
content = f.read()
|
|
302
|
+
|
|
303
|
+
if language not in self.guides:
|
|
304
|
+
# Create new guide
|
|
305
|
+
return self.create_guide(language, content)
|
|
306
|
+
elif append:
|
|
307
|
+
# Append to existing guide
|
|
308
|
+
return self.append_to_guide(language, content)
|
|
309
|
+
else:
|
|
310
|
+
# Replace existing guide
|
|
311
|
+
return self.update_guide(language, content)
|
|
312
|
+
|
|
313
|
+
except Exception as e:
|
|
314
|
+
self.log(f"⚠ Failed to import from {import_path}: {e}")
|
|
315
|
+
return False
|