Last active
August 29, 2015 14:04
-
-
Save bagage/fa738a988781acc579b2 to your computer and use it in GitHub Desktop.
Make Android GUI localizable (move hardcoded android:text to res/values/string.xml and rename in .java)
This file contains 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 | |
try: | |
import sys | |
import readline | |
import re | |
import fileinput | |
from bs4 import BeautifulSoup | |
except Exception as e: | |
print("Please install BeautifulSoup: pip3 install beautifulsoup4") | |
sys.exit(1) | |
def to_camel_case(name): | |
s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) | |
return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() | |
type_conversion = { | |
"button": "btn", | |
"checkbox": "box", | |
"org.runnerup.widget.titlespinner": "", | |
"textview": "txt", | |
} | |
def layout_to_values(filelayout, filestrings): | |
y = BeautifulSoup(open(filelayout).read()) | |
z = BeautifulSoup("xml") | |
for line in fileinput.input(filestrings, inplace=True): | |
if line != "</resources>\n": | |
sys.stdout.write(line) | |
for e in y.findAll(attrs={'android:id': not None}): | |
is_text = e.has_attr("android:text") | |
if is_text: | |
if e["android:text"].startswith("@string/"): | |
is_text = False # no need to treat it | |
if e.name not in type_conversion: | |
print(filelayout + ": not handled type: {}".format(e.name)) | |
previous_id = e["android:id"][e["android:id"].find('/') + 1:] | |
camel_case_id = to_camel_case(previous_id) | |
if previous_id != camel_case_id: | |
# new line separator | |
print() | |
print(filelayout + ": %sID: %25s -----------> %s" % | |
("TEXT" if is_text else "", previous_id, camel_case_id)) | |
# s = input( | |
# "Want to use another ID? (empty to keep this ID{})".format( | |
# "." if is_text else ", * to remove it")) | |
# if not is_text and s == "*": | |
# print(filelayout + ": Remove ID: %25s" % | |
# (camel_case_id)) | |
# camel_case_id = None | |
# elif s: | |
# print(filelayout + ": New ID: %25s -----------> %s" % | |
# (camel_case_id, s)) | |
# camel_case_id = s | |
if is_text and e["android:text"]: # check not empty too | |
new_text_id = camel_case_id | |
if type_conversion[e.name]: | |
new_text_id += "_" + type_conversion[e.name] | |
print(filelayout + ": Text: %25s -----------> %s" % | |
(e["android:text"], "@string/" + new_text_id)) | |
tag = z.new_tag("string") | |
tag.string = e["android:text"] | |
tag["name"] = new_text_id | |
with open(filestrings, "ab") as strings_file: | |
strings_file.write(bytes("\t" + str(tag) + "\n", 'UTF-8')) | |
for line in fileinput.input(filelayout, inplace=True): | |
# we want to delete it | |
if camel_case_id is None: | |
line = line.replace('android:id="@+id/' + previous_id + '"', '') | |
else: | |
line = line.replace(previous_id + '"', camel_case_id + '"') | |
if is_text and e["android:text"]: | |
line = line.replace( | |
"android:text=\"" + e["android:text"] + "\"", | |
"android:text=\"" + "@string/" + new_text_id + "\"") | |
# this is used to write within file | |
print(line, end="") | |
with open(filestrings, "ab") as strings_file: | |
strings_file.write(bytes("</resources>\n", 'UTF-8')) | |
def file_converter(filep): | |
for line in fileinput.input(filep, inplace=True): | |
pattern = "findViewById(R.id." | |
if line.find(pattern) != -1: | |
cast_type = line[line.find('(') + 1:line.find(')')] | |
name = line[line.find(pattern) + len(pattern) - 5:] | |
name = name[:name.find(')')] | |
new_name = "R.id." + to_camel_case(name[5:]) | |
line = line.replace(name, new_name) | |
print(line, end="") | |
if len(sys.argv) < 2: | |
print( | |
"""Give me some args (.xml or .java) | |
Example: {} res/values/strings.xml res/layout*/*.xml $(find src -name '*.java') | |
""".format(sys.argv[0]) | |
) | |
sys.exit(1) | |
xml_file = None | |
for arg in sys.argv[1:]: | |
if arg[-5:] == ".java": | |
file_converter(arg) | |
elif arg[-4:] == ".xml": | |
if not xml_file: | |
xml_file = arg | |
else: | |
layout_to_values(arg, xml_file) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment