mirror of
https://github.com/aphrody-labs/mullvadvpn-app.git
synced 2026-10-13 22:10:39 +00:00
iOS: add update_translations.py script
Run with `python3 update_translations.py` to extract localizable strings from source files and merge them into base localizations (en.lproj)
This commit is contained in:
1 parent
86bb6d0efb
commit
f3ecfb5ecd
3 files changed
+250
No files matched your search
@@ -0,0 +1,14 @@
|
||||
[FORMAT]
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=2
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once).
|
||||
@@ -0,0 +1,42 @@
|
||||
nslocalized==0.2.0 \
|
||||
--hash=sha256:46d6f776b26e9da0e0d0c759d99782884882cade59d5c935005a85cba654db9e
|
||||
## The following requirements were added by pip freeze:
|
||||
astroid==2.6.2
|
||||
cffi==1.14.5 \
|
||||
--hash=sha256:06d7cd1abac2ffd92e65c0609661866709b4b2d82dd15f611e602b9b188b0b69 \
|
||||
--hash=sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06 \
|
||||
--hash=sha256:0f861a89e0043afec2a51fd177a567005847973be86f709bbb044d7f42fc4e05 \
|
||||
--hash=sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73 \
|
||||
--hash=sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49 \
|
||||
--hash=sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4 \
|
||||
--hash=sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62 \
|
||||
--hash=sha256:cc5a8e069b9ebfa22e26d0e6b97d6f9781302fe7f4f2b8776c3e1daea35f1adc \
|
||||
--hash=sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1 \
|
||||
--hash=sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c
|
||||
chardet==4.0.0 \
|
||||
--hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \
|
||||
--hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5
|
||||
click==8.0.1 \
|
||||
--hash=sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a \
|
||||
--hash=sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6
|
||||
GDAL==3.3.1 \
|
||||
--hash=sha256:776ad8f499919d6824b7ba3ae8bd53b2df5d73a14dc047ebc8f33f9507c8dcc5
|
||||
hashin==0.15.0
|
||||
igenstrings==1.1.0
|
||||
isort==5.9.1
|
||||
lazy-object-proxy==1.6.0
|
||||
mccabe==0.6.1
|
||||
packaging==21.0
|
||||
pip-api==0.0.20
|
||||
pycparser==2.20
|
||||
pylint==2.9.3
|
||||
pyparsing==2.4.7
|
||||
six==1.16.0 \
|
||||
--hash=sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926 \
|
||||
--hash=sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254
|
||||
tinycss2==1.1.0 \
|
||||
--hash=sha256:0353b5234bcaee7b1ac7ca3dea7e02cd338a9f8dcbb8f2dcd32a5795ec1e5f9a \
|
||||
--hash=sha256:fbdcac3044d60eb85fdb2aa840ece43cf7dbe798e373e6ee0be545d4d134e18a
|
||||
toml==0.10.2
|
||||
webencodings==0.5.1
|
||||
wrapt==1.12.1
|
||||
@@ -0,0 +1,194 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
A helper script to parse NSLocalizedString in Swift source files and extract and merge new
|
||||
translations with the existing ones.
|
||||
"""
|
||||
|
||||
import os
|
||||
from os import path
|
||||
from subprocess import Popen, PIPE
|
||||
import shutil
|
||||
from nslocalized import StringTable
|
||||
|
||||
# Current script dir
|
||||
SCRIPT_DIR = path.dirname(path.realpath(__file__))
|
||||
|
||||
# Path to directory with source files (Swift)
|
||||
SOURCE_PATH = path.join(SCRIPT_DIR, "MullvadVPN")
|
||||
|
||||
# Path to directory with base localizations
|
||||
BASE_LANGUAGE_PATH = path.join(SOURCE_PATH, "en.lproj")
|
||||
|
||||
# Path to directory with the output of genstrings tool.
|
||||
GENSTRINGS_OUTPUT_PATH = path.join(SCRIPT_DIR, "genstrings-out")
|
||||
|
||||
# Output encoding for strings files.
|
||||
#
|
||||
# By default genstrings tool outputs text in utf-16, which git recognizes as binary, therefore
|
||||
# rendering diff capability useless.
|
||||
#
|
||||
# Store localization files in utf-8 to fix this. Xcode automatically transcodes localization
|
||||
# files to utf-16 during the build phase.
|
||||
OUTPUT_ENCOODING = "utf_8"
|
||||
|
||||
|
||||
def check_file_extension(file, expected_extension):
|
||||
"""
|
||||
Returns True if the file extension matches the expected one.
|
||||
"""
|
||||
(_basename, ext) = os.path.splitext(file)
|
||||
return ext == expected_extension
|
||||
|
||||
|
||||
def get_source_files():
|
||||
"""
|
||||
Find all Swift source files recursively.
|
||||
"""
|
||||
results = []
|
||||
for root, _dirs, files in os.walk(SOURCE_PATH):
|
||||
for file in files:
|
||||
if check_file_extension(file, ".swift"):
|
||||
results.append(path.join(root, file))
|
||||
return results
|
||||
|
||||
|
||||
def get_strings_files(dir_path):
|
||||
"""
|
||||
Find all .strings files within the given directory.
|
||||
"""
|
||||
results = []
|
||||
for file in os.listdir(dir_path):
|
||||
if check_file_extension(file, ".strings"):
|
||||
results.append(file)
|
||||
return results
|
||||
|
||||
|
||||
def create_empty_output_dir():
|
||||
"""
|
||||
Creates empty directory for output of genstrings tool.
|
||||
"""
|
||||
# Wipe out old files
|
||||
delete_output_dir()
|
||||
|
||||
# Re-create out directory
|
||||
os.mkdir(GENSTRINGS_OUTPUT_PATH)
|
||||
|
||||
|
||||
def delete_output_dir():
|
||||
"""
|
||||
Delete directory used for genstrings output
|
||||
"""
|
||||
if path.exists(GENSTRINGS_OUTPUT_PATH):
|
||||
shutil.rmtree(GENSTRINGS_OUTPUT_PATH)
|
||||
|
||||
|
||||
def extract_translations():
|
||||
"""
|
||||
Extract translations from sources using genstrings tool.
|
||||
"""
|
||||
|
||||
# Get Swift source files
|
||||
source_files = get_source_files()
|
||||
|
||||
# Genstrings utility comes with Xcode and used for extracting the localizable strings from source
|
||||
# files and producing string tables.
|
||||
args = (
|
||||
"genstrings", "-o", GENSTRINGS_OUTPUT_PATH,
|
||||
*source_files
|
||||
)
|
||||
(exit_code, errors) = run_program(*args)
|
||||
|
||||
if exit_code == 0:
|
||||
print("Genstrings finished without errors.")
|
||||
else:
|
||||
print("Genstrings exited with {}: {}".format(exit_code, errors.decode().strip()))
|
||||
|
||||
|
||||
def merge_translations():
|
||||
"""
|
||||
Merge string tables, delete stale ones and copy new ones.
|
||||
"""
|
||||
|
||||
# Existing string tables
|
||||
existing_string_tables = get_strings_files(BASE_LANGUAGE_PATH)
|
||||
|
||||
# Newly generated string tables
|
||||
new_string_tables = get_strings_files(GENSTRINGS_OUTPUT_PATH)
|
||||
|
||||
# String tables that will be merged
|
||||
merge_string_tables = []
|
||||
|
||||
# Detect new string tables
|
||||
for table_name in new_string_tables:
|
||||
if table_name not in existing_string_tables:
|
||||
src = path.join(GENSTRINGS_OUTPUT_PATH, table_name)
|
||||
dst = path.join(BASE_LANGUAGE_PATH, table_name)
|
||||
|
||||
print("Copying {} to {}".format(src, dst))
|
||||
new_table = StringTable.read(src)
|
||||
new_table.write(dst, encoding=OUTPUT_ENCOODING)
|
||||
|
||||
# Detect removed string tables
|
||||
for table_name in existing_string_tables:
|
||||
if table_name in new_string_tables:
|
||||
merge_string_tables.append(table_name)
|
||||
else:
|
||||
filepath = path.join(BASE_LANGUAGE_PATH, table_name)
|
||||
|
||||
print("Removing {}".format(filepath))
|
||||
os.unlink(filepath)
|
||||
|
||||
# Merge remaining string tables
|
||||
for table_name in merge_string_tables:
|
||||
new_table_path = path.join(GENSTRINGS_OUTPUT_PATH, table_name)
|
||||
base_table_path = path.join(BASE_LANGUAGE_PATH, table_name)
|
||||
|
||||
merge_two_tables(base_table_path, new_table_path)
|
||||
|
||||
|
||||
def merge_two_tables(base_table_path, new_table_path):
|
||||
"""
|
||||
Merge new table into base table.
|
||||
"""
|
||||
# Existing string table previously generated from sources
|
||||
base_table = StringTable.read(base_table_path)
|
||||
|
||||
# New string table generated from sources
|
||||
new_table = StringTable.read(new_table_path)
|
||||
|
||||
print("Merging {} into {}".format(new_table_path, base_table_path))
|
||||
|
||||
# Iterate through newly generated table and preserve existing translations.
|
||||
for new_key in new_table.strings:
|
||||
base_entry = base_table.lookup(new_key)
|
||||
new_entry = new_table.lookup(new_key)
|
||||
if base_entry is not None:
|
||||
new_entry.target = base_entry.target
|
||||
|
||||
print("Write {} on disk.".format(base_table_path))
|
||||
new_table.write(base_table_path, encoding=OUTPUT_ENCOODING)
|
||||
|
||||
|
||||
def run_program(*args):
|
||||
"""
|
||||
Run program and return a tuple with returncode and errors.
|
||||
"""
|
||||
with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE) as subproc:
|
||||
print("Run: {}".format(' '.join(args)))
|
||||
|
||||
errors = subproc.communicate()[1]
|
||||
return (subproc.returncode, errors)
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Program entry
|
||||
"""
|
||||
create_empty_output_dir()
|
||||
extract_translations()
|
||||
merge_translations()
|
||||
delete_output_dir()
|
||||
|
||||
|
||||
main()
|
||||
Reference in new issue
Block a user