mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-07-22 20:26:50 +00:00
Update transaltions
This commit is contained in:
@@ -1,108 +0,0 @@
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import csv
|
||||
import argparse
|
||||
|
||||
# Customize as needed
|
||||
I18N_FUNCTIONS = ['t', 'i18next.t']
|
||||
FILE_EXTENSIONS = ['.tsx', '.ts']
|
||||
EXCLUDED_DIRS = ['node_modules', 'build', 'dist']
|
||||
|
||||
# Regex patterns
|
||||
STRING_LITERAL_REGEX = re.compile(r'(?<!t\()\s*["\']([A-Z][^"\']{2,})["\']')
|
||||
JSX_TEXT_REGEX = re.compile(r'>\s*([A-Z][a-z].*?)\s*<')
|
||||
|
||||
def is_excluded(path):
|
||||
return any(excluded in path for excluded in EXCLUDED_DIRS)
|
||||
|
||||
def is_ignorable(text, line):
|
||||
if re.fullmatch(r'[A-Z0-9_]+', text):
|
||||
if re.search(r'\b(case|action|status)\b', line, re.IGNORECASE):
|
||||
return True
|
||||
return False
|
||||
|
||||
def is_console_log_line(line):
|
||||
return any(kw in line for kw in ['console.log', 'console.error', 'console.warn'])
|
||||
|
||||
def find_untranslated_strings(file_path):
|
||||
issues = []
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
lines = content.splitlines()
|
||||
|
||||
for idx, line in enumerate(lines, start=1):
|
||||
if is_console_log_line(line):
|
||||
continue # Skip entire line if it's a console log statement
|
||||
|
||||
# Match suspicious string literals
|
||||
for match in STRING_LITERAL_REGEX.finditer(line):
|
||||
string = match.group(1).strip()
|
||||
if is_ignorable(string, line):
|
||||
continue
|
||||
if not any(fn + '(' in line[:match.start()] for fn in I18N_FUNCTIONS):
|
||||
issues.append({
|
||||
'file': file_path,
|
||||
'line': idx,
|
||||
'type': 'StringLiteral',
|
||||
'text': string
|
||||
})
|
||||
|
||||
# Match JSX text nodes
|
||||
for match in JSX_TEXT_REGEX.finditer(line):
|
||||
text = match.group(1).strip()
|
||||
if is_ignorable(text, line):
|
||||
continue
|
||||
if not text.startswith('{t('):
|
||||
issues.append({
|
||||
'file': file_path,
|
||||
'line': idx,
|
||||
'type': 'JSXText',
|
||||
'text': text
|
||||
})
|
||||
|
||||
return issues
|
||||
|
||||
|
||||
def scan_directory(directory):
|
||||
all_issues = []
|
||||
for root, _, files in os.walk(directory):
|
||||
if is_excluded(root):
|
||||
continue
|
||||
for file in files:
|
||||
if any(file.endswith(ext) for ext in FILE_EXTENSIONS):
|
||||
file_path = os.path.join(root, file)
|
||||
issues = find_untranslated_strings(file_path)
|
||||
all_issues.extend(issues)
|
||||
return all_issues
|
||||
|
||||
def save_report(results, output_file):
|
||||
_, ext = os.path.splitext(output_file)
|
||||
if ext.lower() == '.json':
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(results, f, indent=2)
|
||||
elif ext.lower() == '.csv':
|
||||
with open(output_file, 'w', newline='', encoding='utf-8') as f:
|
||||
writer = csv.DictWriter(f, fieldnames=['file', 'line', 'type', 'text'])
|
||||
writer.writeheader()
|
||||
for row in results:
|
||||
writer.writerow(row)
|
||||
else:
|
||||
raise ValueError("Unsupported output format. Use .json or .csv")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Detect untranslated strings in React (.tsx) files.')
|
||||
parser.add_argument('-path', default='../src/', help='Path to the source directory (e.g. ./src)')
|
||||
parser.add_argument('-o', '--output', default='./i18n_report.json', help='Report output file (.json or .csv)')
|
||||
|
||||
args = parser.parse_args()
|
||||
results = scan_directory(args.path)
|
||||
|
||||
if results:
|
||||
save_report(results, args.output)
|
||||
print(f"⚠️ Found {len(results)} potential untranslated strings. Report saved to {args.output}")
|
||||
else:
|
||||
print("✅ No obvious untranslated strings found.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
61
scripts/i18n_translate_json.py
Normal file
61
scripts/i18n_translate_json.py
Normal file
@@ -0,0 +1,61 @@
|
||||
import os
|
||||
import json
|
||||
from deep_translator import GoogleTranslator
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
# === CONFIGURATION ===
|
||||
base_folder = "../src/i18n/locales"
|
||||
source_lang = "en"
|
||||
target_langs = ["de", "es", "fr", "it", "ja", "ru", "zh_CN"]
|
||||
filenames = ["auth.json", "core.json", "group.json", "question.json", "tutorial.json"]
|
||||
max_workers = 12 # Adjust based on your CPU
|
||||
|
||||
# === TRANSLATION FUNCTION ===
|
||||
def translate_json(obj, target_lang):
|
||||
if isinstance(obj, dict):
|
||||
return {k: translate_json(v, target_lang) for k, v in obj.items()}
|
||||
elif isinstance(obj, list):
|
||||
return [translate_json(item, target_lang) for item in obj]
|
||||
elif isinstance(obj, str):
|
||||
if "{{" in obj or "}}" in obj or "<" in obj:
|
||||
return obj # Skip templating/markup
|
||||
try:
|
||||
return GoogleTranslator(source='en', target=target_lang).translate(text=obj)
|
||||
except Exception as e:
|
||||
print(f"[{target_lang}] Error: {e}")
|
||||
return obj
|
||||
return obj
|
||||
|
||||
# === WORKER FUNCTION ===
|
||||
def translate_file_for_lang(filename, data, lang):
|
||||
print(f"🔁 Translating {filename} → {lang}")
|
||||
translated = translate_json(data, lang)
|
||||
target_dir = os.path.join(base_folder, lang)
|
||||
os.makedirs(target_dir, exist_ok=True)
|
||||
target_path = os.path.join(target_dir, filename)
|
||||
with open(target_path, "w", encoding="utf-8") as f:
|
||||
json.dump(translated, f, ensure_ascii=False, indent=2)
|
||||
print(f"✅ Saved {target_path}")
|
||||
return target_path
|
||||
|
||||
# === MAIN FUNCTION ===
|
||||
def main():
|
||||
tasks = []
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
for filename in filenames:
|
||||
source_path = os.path.join(base_folder, source_lang, filename)
|
||||
if not os.path.isfile(source_path):
|
||||
print(f"⚠️ Missing file: {source_path}")
|
||||
continue
|
||||
|
||||
with open(source_path, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
for lang in target_langs:
|
||||
tasks.append(executor.submit(translate_file_for_lang, filename, data, lang))
|
||||
|
||||
for future in as_completed(tasks):
|
||||
_ = future.result()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Reference in New Issue
Block a user