Created
October 23, 2023 10:46
-
-
Save liudasbar/c2f93546b99e493577fb0754742786c9 to your computer and use it in GitHub Desktop.
Localizable strings generator for Swift projects in Xcode
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
import os | |
def parse_input(input_path): | |
with open(input_path, 'r') as f: | |
lines = f.readlines() | |
translations = {} | |
for line in lines: | |
line = line.strip() | |
if not line.startswith('"') or '=' not in line: | |
continue | |
key, value = line.split('=', 1) | |
key = key.strip('" ') | |
value = value.strip(' ";') | |
translations[key] = value | |
return translations | |
def build_translation_tree(translations): | |
tree = {} | |
for key, value in translations.items(): | |
parts = key.split('.') | |
node = tree | |
for part in parts: | |
if part not in node: | |
node[part] = {} | |
node = node[part] | |
node['value'] = key | |
return tree | |
def to_struct_name(name): | |
parts = name.split('.') | |
if len(parts) > 1: | |
return parts[-2] | |
return parts[0] | |
def generate_swift_code(t, translations, depth=1): | |
code = "" | |
indentation = ' ' * depth | |
for key, subtree in t.items(): | |
if key == 'value': | |
continue | |
if 'value' in subtree: | |
# Check if the translation value has a placeholder | |
has_placeholder = "%@" in translations[subtree["value"]] | |
if has_placeholder: | |
code += f'{indentation}public static func {key}(_ value: String) -> String {{\n' | |
code += f'{indentation} return String(format: NSLocalizedString("{subtree["value"]}", comment: ""), value)\n' | |
code += f'{indentation}}}\n' | |
else: | |
code += f'{indentation}public static var {key}: String {{\n' | |
code += f'{indentation} return NSLocalizedString("{subtree["value"]}", comment: "")\n' | |
code += f'{indentation}}}\n' | |
else: | |
struct_name = to_struct_name(key) | |
code += f'{indentation}public struct {struct_name} {{\n' | |
code += generate_swift_code(subtree, translations, depth + 1) | |
code += f'{indentation}}}\n' | |
return code | |
def main(): | |
input_file_path = './Path/To/Localizable.strings/File' | |
output_file_path = './Path/To/Strings.swift/File' | |
translations = parse_input(input_file_path) | |
translations_tree = build_translation_tree(translations) | |
output = 'public struct Strings {\n' | |
output += ' // MARK: - Common\n' | |
for key, subtree in translations_tree.items(): | |
struct_name = to_struct_name(key) | |
if 'value' in subtree: | |
output += f' public static var {key}: String {{\n' | |
output += f' NSLocalizedString("{subtree["value"]}", comment: "")\n' | |
output += ' }\n' | |
else: | |
output += f' public struct {struct_name} {{\n' | |
output += generate_swift_code(subtree, translations, 2) | |
output += ' }\n' | |
output += '}\n' | |
with open(output_file_path, 'w') as f: | |
f.write(output) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Setup instructions:
This generation supports nested strings. It also supports single formatted string value (can be declared as "%@" in Localizable.strings file, e.g.
"User.header" = "User %@";
. So you can use it like this:Strings.User.header(userName)