Skip to content

Instantly share code, notes, and snippets.

@flodolo
Last active May 13, 2025 08:01
Show Gist options
  • Save flodolo/a64de8a09e80dae7d40c37a3d4112bbb to your computer and use it in GitHub Desktop.
Save flodolo/a64de8a09e80dae7d40c37a3d4112bbb to your computer and use it in GitHub Desktop.
Firefox iOS completetion stats based on .strings files
#!/usr/bin/env python3
"""
Script to determine localization completion based on .strings files.
"""
import re
import sys
from pathlib import Path
def find_strings_files(locale: str, root: Path):
"""Recursively find all .strings files in en-US.lproj directories."""
search_path = root / "firefox-ios"
return search_path.rglob(f"{locale}.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 find_locales(root: Path):
"""Guess locales from firefox-ios/Client/*.lproj folders."""
search_path = root / "firefox-ios" / "Client"
folders = search_path.glob("*.lproj")
locales = [
str(locale.relative_to(search_path)).removesuffix(".lproj")
for locale in folders
if locale.is_dir() and locale.name not in ["en-US.lproj", "en.lproj"]
]
locales.sort()
return locales
def main(root_dir: Path):
ref_locale = "en-US"
# Gather all keys from the en-US .strings files
reference_keys = set()
for strings_file in find_strings_files(ref_locale, root_dir):
reference_keys.update(extract_keys_from_strings_file(strings_file, root_dir))
locales = find_locales(root_dir)
stats = {}
total_ref_keys = len(reference_keys)
for locale in locales:
missing = 0
# Gather all keys from the locale .strings files
locale_keys = set()
for strings_file in find_strings_files(locale, root_dir):
locale_keys.update(extract_keys_from_strings_file(strings_file, root_dir))
for ref_key in reference_keys:
if ref_key.replace(ref_locale, locale) not in locale_keys:
missing += 1
stats[locale] = {
"missing": missing,
"total": len(locale_keys),
"completion": round(((total_ref_keys - missing) / total_ref_keys) * 100, 2),
}
print("Locale completion stats:")
for locale in locales:
print(f" {locale}: {stats[locale]['completion']}%")
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