- Ein-/Ausklappen wieder mit schwarzem Pfeil (>/v) ohne Box. - Neuer Tab Shortcodes; Darstellung listet keine Funktionen mehr. - CSS-Klassen-Referenz in den Darstellung-Tab (unter Custom CSS) verschoben. - EN-Uebersetzung (121 Strings) neu gebaut. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
184 lines
7.3 KiB
Python
184 lines
7.3 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""Build gdpr-content-blocker-en_US.po + .mo from strings.txt (German keys in
|
|
file order) + the EN list below (same order)."""
|
|
import struct, sys, os
|
|
|
|
EN = [
|
|
"Invalid response from the license server.",
|
|
"Insufficient permissions.",
|
|
"Please enter a license key.",
|
|
"License activated successfully.",
|
|
"All seats for this license are in use. Release a domain to activate this site.",
|
|
"Activation failed.",
|
|
"Please select a valid domain to release.",
|
|
"Released %s and activated this site.",
|
|
"License is no longer valid.",
|
|
"GDPR Content Blocker is not licensed. Protection stays active, but please add a %s for updates and support.",
|
|
"License key",
|
|
"Active",
|
|
"Invalid",
|
|
"All seats in use",
|
|
"Not activated",
|
|
"Status",
|
|
"Domain",
|
|
"Release domain",
|
|
"This license is already active on the domains listed. Choose one to release — it will be deactivated and this site activated instead.",
|
|
"Release and activate this site",
|
|
"Hidden for security. To change it, deactivate first.",
|
|
"Deactivate license",
|
|
"Try again",
|
|
"Activate license",
|
|
"Recipient:",
|
|
"Purpose:",
|
|
"⚠ Data transfer to a third country outside the EU/EEA",
|
|
"Provider's privacy policy",
|
|
"Load %s now",
|
|
"Always load this service from now on",
|
|
"Loading this content from %s requires your consent. Personal data (e.g. your IP address) will be transmitted to the provider.",
|
|
"Withdraw consent for external content",
|
|
"Affects only the release of external embeds (e.g. maps, videos). Cookie settings are managed separately.",
|
|
"Transfer to a third country outside the EU/EEA",
|
|
"Recipient",
|
|
"Purpose",
|
|
"Sets cookies",
|
|
"Yes",
|
|
"No",
|
|
"Privacy policy",
|
|
"GDPR Content Blocker",
|
|
"Really remove this service?",
|
|
"New service",
|
|
"Scanning website …",
|
|
"Scan failed:",
|
|
"No external resources found.",
|
|
"Provider / Host",
|
|
"Type",
|
|
"Count",
|
|
"Example URL",
|
|
"Action",
|
|
"covered",
|
|
"third party",
|
|
"own domain",
|
|
"Add as service",
|
|
"Use template",
|
|
"Template available",
|
|
"Scanned pages:",
|
|
"Found on",
|
|
"Google Ireland Ltd., Ireland / Google LLC, USA",
|
|
"Display of interactive maps and location information.",
|
|
"Embedding and playback of videos.",
|
|
"OpenStreetMap Foundation, United Kingdom",
|
|
"Display of interactive maps.",
|
|
"Vimeo LLC, USA",
|
|
"Settings saved.",
|
|
"Services",
|
|
"Scan",
|
|
"Appearance",
|
|
"Shortcodes",
|
|
"License",
|
|
"About the plugin",
|
|
"+ Add empty service",
|
|
"— Insert template —",
|
|
"Save services",
|
|
"The license server visits your website and lists all embedded third-party resources (iframes, scripts, fonts, images, …). This shows at a glance which external services you should block. Requires an active license.",
|
|
"Scan website",
|
|
"Save appearance",
|
|
"new",
|
|
"Show/hide details",
|
|
"Blocker on/off",
|
|
"Remove service",
|
|
"Internal name (slug)",
|
|
"Provider name",
|
|
"Detection pattern (domain/path)",
|
|
"Recipient (incl. country)",
|
|
"Provider's privacy policy URL",
|
|
"Processing purpose",
|
|
"Custom placeholder text (empty = default)",
|
|
"Data transfer to a third country (outside EU/EEA)",
|
|
"Loads external scripts",
|
|
"Placeholder text color",
|
|
"Placeholder background color",
|
|
"Button: background color",
|
|
"Button: text color",
|
|
"Button hover: background color",
|
|
"Button hover: text color",
|
|
"Custom CSS",
|
|
"Loaded after the CSS variables and can override them. Tip: use the same prefix, e.g. .cb-blocker .cb-blocker__button { … }",
|
|
"CSS classes:",
|
|
"Withdrawal (privacy policy)",
|
|
"Renders a clearly visible link that withdraws consent for external embeds and reloads the page (Art. 7(3) GDPR). Does NOT affect the cookie consent of a separate cookie plugin. Options: text=\"…\", style=\"link|button\", note=\"yes|no\".",
|
|
"Block content manually",
|
|
"Wraps an iframe and replaces it with the placeholder of the given service. Use the internal name from the \"Services\" tab.",
|
|
"Services overview (privacy policy)",
|
|
"Lists all configured services with recipient, third-country note, purpose and privacy link. Ideal for inclusion in your privacy policy (Art. 13 GDPR).",
|
|
"Version %s",
|
|
"GDPR Content Blocker loads external embeds (e.g. Google Maps, YouTube, OpenStreetMap, Vimeo) only after the visitor actively consents. Before the click no connection to the third party is made — so no personal data (e.g. the IP address) is transmitted. This lets you embed external content in a GDPR-compliant way without a heavy consent tool.",
|
|
"Features",
|
|
"True click-to-load (no preloaded iframe)",
|
|
"Granular consent per service",
|
|
"Art.-13-compliant placeholder with recipient, purpose, third-country note and privacy link",
|
|
"Easy withdrawal via shortcode (Art. 7(3) GDPR)",
|
|
"Automatic detection of common providers + manual shortcode",
|
|
"Legal",
|
|
"Imprint",
|
|
"Privacy policy",
|
|
"Note: This plugin is a technical tool and does not constitute legal advice. The site operator is responsible for the legally compliant configuration (recipients, purposes, privacy policy).",
|
|
"Developed by %s",
|
|
"Please activate a license first (\"License\" tab).",
|
|
"Unexpected response from the license server.",
|
|
]
|
|
|
|
base = sys.argv[1]
|
|
strings_file = os.path.join(base, 'hilfsdaten', 'strings.txt')
|
|
de = []
|
|
with open(strings_file, encoding='utf-8') as f:
|
|
for line in f:
|
|
if line.startswith('MSGID\t'):
|
|
de.append(line[len('MSGID\t'):].rstrip('\n'))
|
|
|
|
if len(de) != len(EN):
|
|
print(f"MISMATCH: {len(de)} German vs {len(EN)} English"); sys.exit(1)
|
|
|
|
header = ("Project-Id-Version: GDPR Content Blocker\n"
|
|
"MIME-Version: 1.0\n"
|
|
"Content-Type: text/plain; charset=UTF-8\n"
|
|
"Content-Transfer-Encoding: 8bit\n"
|
|
"Language: en_US\n")
|
|
entries = {'': header}
|
|
for d, e in zip(de, EN):
|
|
entries[d] = e
|
|
|
|
def po_escape(s):
|
|
return s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n')
|
|
|
|
po_path = os.path.join(base, 'gdpr-content-blocker', 'languages', 'gdpr-content-blocker-en_US.po')
|
|
with open(po_path, 'w', encoding='utf-8') as f:
|
|
f.write('msgid ""\nmsgstr ""\n')
|
|
for line in header.rstrip('\n').split('\n'):
|
|
f.write('"%s\\n"\n' % po_escape(line))
|
|
f.write('\n')
|
|
for d, e in zip(de, EN):
|
|
f.write('msgid "%s"\n' % po_escape(d))
|
|
f.write('msgstr "%s"\n\n' % po_escape(e))
|
|
|
|
def write_mo(entries, out):
|
|
keys = sorted(entries.keys())
|
|
ids = b''; strs = b''; offsets = []
|
|
for k in keys:
|
|
kb = k.encode('utf-8'); vb = entries[k].encode('utf-8')
|
|
offsets.append((len(ids), len(kb), len(strs), len(vb)))
|
|
ids += kb + b'\x00'; strs += vb + b'\x00'
|
|
keystart = 7 * 4 + 16 * len(keys)
|
|
valuestart = keystart + len(ids)
|
|
ko = []; vo = []
|
|
for o1, l1, o2, l2 in offsets:
|
|
ko += [l1, o1 + keystart]; vo += [l2, o2 + valuestart]
|
|
out_b = struct.pack("Iiiiiii", 0x950412de, 0, len(keys), 7 * 4, 7 * 4 + len(keys) * 8, 0, 0)
|
|
out_b += struct.pack("i" * len(ko), *ko) + struct.pack("i" * len(vo), *vo) + ids + strs
|
|
with open(out, 'wb') as f:
|
|
f.write(out_b)
|
|
|
|
mo_path = os.path.join(base, 'gdpr-content-blocker', 'languages', 'gdpr-content-blocker-en_US.mo')
|
|
write_mo(entries, mo_path)
|
|
print(f"OK: {len(de)} strings -> {os.path.basename(po_path)} + .mo")
|