Skip to content

Instantly share code, notes, and snippets.

@akfreas
Created January 18, 2024 10:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akfreas/28fd30f6ae91f79003a0bf0b2beb8bf4 to your computer and use it in GitHub Desktop.
Save akfreas/28fd30f6ae91f79003a0bf0b2beb8bf4 to your computer and use it in GitHub Desktop.
Auto Translate iOS Strings
#!/usr/bin/env python3
import argparse
import os
import openai
from pprint import pprint
import os
from openai import OpenAI
from tqdm import tqdm
client = OpenAI(
# This is the default and can be omitted
api_key=os.environ.get("OPENAI_API_KEY"),
)
def translate_text(text, source_lang, target_lang_code, app_context, filename_comment):
languages = {
"en": "English",
"es": "Spanish",
"fr": "French",
"de": "German",
"it": "Italian",
"ja": "Japanese",
"ko": "Korean",
"pt": "Portuguese",
"ru": "Russian",
}
target_lang = languages[target_lang_code]
prompt = f"Translate the following iOS app strings from {source_lang} to {target_lang}, keeping the format intact.\n{text}"
system = f"""
You are translating strings from an app from English to {target_lang}.
Do not translate the keys (left side of the = sign), only the values.
If the string is already in {target_lang}, and the meaning is not significantly different than the existing string, you can leave it as is.
{app_context}
"""
messages = [
{"role": "system", "content": system},
{"role": "user", "content": prompt}
]
print("Translating chunk:", filename_comment)
response = client.chat.completions.create(model="gpt-4-1106-preview", messages=messages)
print(f"Finished translating chunk: {filename_comment}. Used {response.usage.total_tokens} tokens.")
return response.choices[0].message.content
def parse_localization_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
lines = file.readlines()
localization_dict = {}
current_file = None
for line in lines:
line = line.strip()
if line.startswith('/*') and line.endswith('*/'):
current_file = line[2:-2].strip()
elif '=' in line:
key_value = line.split('=')
key = key_value[0].strip().strip('"')
value = key_value[1].strip().strip('";')
if current_file not in localization_dict:
localization_dict[current_file] = []
localization_dict[current_file].append({'key': key, 'value': value})
return localization_dict
def write_translations(localization_dict, target_lang_code, app_context_path, target_directory):
if "lproj" in target_directory:
print("Target directory should be the directory that contains the lproj directories, not the lproj directory itself")
return
if not os.path.exists(target_directory):
print("Target directory not found")
return
directory = os.path.join(target_directory, f"{target_lang_code}.lproj")
if os.path.exists(directory):
print(f"Target directory {directory} already exists. Overwrite? [y/n]")
response = input()
if response.lower() != 'y':
return
if not os.path.exists(app_context_path):
print("App context file not found")
return
with open(app_context_path, 'r', encoding='utf-8') as file:
app_context = file.read()
os.makedirs(directory, exist_ok=True)
with open(os.path.join(directory, "Localizable.strings"), 'w', encoding='utf-8') as file:
# Wrap localization_dict.items() with tqdm for progress tracking
for filename_comment, texts in tqdm(localization_dict.items(), desc="Processing", unit="chunk"):
text = list(map(lambda text: f"\"{text['key']}\" = \"{text['value']}\";", texts))
joined = "\n".join(text)
translated_text = translate_text(joined, "English", target_lang_code, app_context, filename_comment)
file.write(f"/* {filename_comment} */\n{translated_text} \n\n")
print("Wrote translated chunk to file:", filename_comment)
def main():
parser = argparse.ArgumentParser(description="Localize iOS app strings")
parser.add_argument("--source_file", type=str, help="Path to the source localization file", required=True)
parser.add_argument("--target_dir", type=str, help="Path to the target strings resource directory", required=True)
parser.add_argument("--target_lang_code", type=str, help="Target language for translation", required=True)
parser.add_argument("--app_context", type=str, help="Path to the app context file that describes the app that the strings are from", required=True)
args = parser.parse_args()
localization_data = parse_localization_file(args.source_file)
write_translations(localization_data, args.target_lang_code, args.app_context, args.target_dir)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment