Created
May 12, 2025 09:19
-
-
Save flodolo/de2eb7bc74888c5aa556af8a3a6bf3e3 to your computer and use it in GitHub Desktop.
Identify strings in en-US .strings files but not available in Strings.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Script to find unused localized string IDs in .strings files under en-US.lproj | |
folders by checking their definitions in firefox-ios/Shared/Strings.swift. | |
""" | |
import re | |
import sys | |
from pathlib import Path | |
def find_strings_files(root: Path): | |
"""Recursively find all .strings files in en-US.lproj directories.""" | |
search_path = root / "firefox-ios" | |
return search_path.rglob("en-US.lproj/*.strings") | |
def extract_keys_from_strings_file(strings_path: Path, root: Path): | |
"""Extract all keys from a .strings file.""" | |
pattern = re.compile(r'^\s*"([^"]+)"\s*=') | |
keys = [] | |
strings_rel_path = strings_path.relative_to(root) | |
with strings_path.open("r", encoding="utf-8") as f: | |
for line in f: | |
match = pattern.match(line) | |
if match: | |
keys.append(f"{strings_rel_path}:{match.group(1)}") | |
return keys | |
def extract_defined_keys_from_swift(swift_path: Path): | |
"""Extract all keys defined in Strings.swift via MZLocalizedString calls.""" | |
pattern = re.compile(r'key:\s*"([^"]+)"') | |
content = swift_path.read_text(encoding="utf-8") | |
return pattern.findall(content) | |
# List of string IDs to exclude from unused report | |
excluded_ids = set( | |
[ | |
"firefox-ios/Client/en-US.lproj/InfoPlist.strings:NSCameraUsageDescription", | |
"firefox-ios/Client/en-US.lproj/InfoPlist.strings:NSFaceIDUsageDescription", | |
"firefox-ios/Client/en-US.lproj/InfoPlist.strings:NSLocationWhenInUseUsageDescription", | |
"firefox-ios/Client/en-US.lproj/InfoPlist.strings:NSMicrophoneUsageDescription", | |
"firefox-ios/Client/en-US.lproj/InfoPlist.strings:NSPhotoLibraryAddUsageDescription", | |
"firefox-ios/Client/en-US.lproj/InfoPlist.strings:New Private Tab", | |
"firefox-ios/Client/en-US.lproj/InfoPlist.strings:Scan QR Code", | |
"firefox-ios/Shared/en-US.lproj/Default Browser.strings:DefaultBrowserCard.Button.v2", | |
"firefox-ios/Shared/en-US.lproj/Localizable.strings:A username and password are being requested by %@. The site says: %@", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:2GqvPe", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:PzSrmZ-2GqvPe", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:PzSrmZ-eHmH1H", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:PzSrmZ-scEmjs", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:PzSrmZ-xRJbBP", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:ctDNmu", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:eHmH1H", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:eV8mOT", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:eqyNJg", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:fi3W24-2GqvPe", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:fi3W24-eHmH1H", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:fi3W24-scEmjs", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:fi3W24-xRJbBP", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:scEmjs", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:w9jdPK", | |
"firefox-ios/WidgetKit/en-US.lproj/WidgetIntents.strings:xRJbBP", | |
] | |
) | |
def main(root_dir: Path): | |
# Locate Strings.swift | |
swift_file = root_dir / "firefox-ios" / "Shared" / "Strings.swift" | |
if not swift_file.exists(): | |
print(f"Error: Strings.swift not found at {swift_file}", file=sys.stderr) | |
sys.exit(1) | |
# Gather all keys from .strings files | |
all_keys = set() | |
for strings_file in find_strings_files(root_dir): | |
all_keys.update(extract_keys_from_strings_file(strings_file, root_dir)) | |
# Gather all keys defined in Strings.swift | |
defined_keys = set(extract_defined_keys_from_swift(swift_file)) | |
unused_keys = set() | |
# Compute unused keys | |
for key in all_keys: | |
id = key.split(":")[1] | |
if key in excluded_ids: | |
continue | |
if id not in defined_keys: | |
unused_keys.add(key) | |
unused_keys = sorted(unused_keys) | |
if unused_keys: | |
for key in unused_keys: | |
print(f"Unused string ID: {key}") | |
else: | |
print("No unused string IDs found.") | |
if __name__ == "__main__": | |
root = ( | |
Path(sys.argv[1]) | |
if len(sys.argv) > 1 | |
else sys.exit("Provide the path to the Firefox iOS repo.") | |
) | |
main(root) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment