-
Notifications
You must be signed in to change notification settings - Fork 2
How I programmed multi language support in Wheeler's Wort Works
Firstly, I thought, maybe it would be a good idea to follow a system that I've worked with in the past. That being Localazy in combination with GNU GetText. Clearly this API is very stable, and I thought it would be a good idea... But then I realised there was an issue with this, this meant more and more code in Wheeler's Wort Works was moving away from what it was meant to be in the past: a very simple community program, with understandable code.. The point was to hopefully release an alternative to Wheeler's Beer Engine, with an open-source nature that would allow more people to access it or reprogram it for their own needs.
One can see that my code, although it doesn't use GNU GetText, it was heavily influenced by the basic system applied within GNU GetText:
I could probably have used it with GNU GetText, but personally, I didn't like the way I had to structure my program.. As a mathematician, and a programmer, seeing those many layers of brackets (_('dkskads)9)0(-'))
, just didn't seem like what I wanted, and it would have had complications with the update.py
system too, as things such as "folder" creation would need to be implemented. And you know what happens when trying to make folders in a root scenario? That's right, unnecessary write permissions. So instead, to help my fellow Ubuntu/Debian users, I have created this software to use a JSON file, instead of a complicated folder system!
The JSON file system, basically works by creating a Python Dictionary, and taking the English phrases, and giving them another value returned. I hope this makes sense to my fellow developers? So the system works by, giving the dictionary (named _
after GetText), a key (_['Hello']
) and in response, the system returns the value from the locale (i.e. _['Hello'] -> 'Guten Tag'
)
An extract from the JSON file:
{
"en":{
"Recipe Name:":"Recipe Name:",
"Volume:":"Volume:",
"Boil Volume:":"Boil Volume:",
"Remove":"Remove",
"Add New":"Add New",
"Adjust Weight":"Adjust Weight",
"Original Gravity":"Original Gravity",
...
}
}
AUTOMATION! AUTOMATION! AUTOMATION!
As it says on thinkautomation
:
Just because you can automate something, it doesn’t follow that it should be automated. I disagree, because this is something that should be automated, let's look at my rubbish code to automate this:
# coding=utf8
# the above tag defines encoding for this document and is for Python 2.x compatibility
import re
import itertools
regexes = [r"(text=)'''(.*)'''", r'(text=)\"(.+?)\"', r"(text=)\'(.+?)\'", r"(label=)'''(.*)'''", r'(label=)\"(.+?)\"', r"(label=)\'(.+?)\'"]
test_str = open('beer_engine.py', 'r', encoding='utf8').read()
def get_text(regex, text):
matches = re.finditer(regex, text, re.MULTILINE)
return [match.groups() for matchNum, match in enumerate(matches, start=1) if match.groups()[1][0].isalpha()]
translatable = list(itertools.chain.from_iterable([get_text(regex, test_str) for regex in regexes]))
translate_dict = {'en': {}}
remove = ['L/kg', 'LDK', 'EBC']
add = ['Final Volume:', 'Original Gravity:', 'Final Gravity:', 'Alcohol Content:', 'Mash Efficiency:', 'Bitterness:', 'Colour:', 'Notes', 'Efficiency:', 'Alcohol (ABV):', 'Mash Liquor:']
add += ['Use the debian mode (only use on a Debian/Ubuntu system)', 'Use the local mode', 'Pull `update.py` from GitHub, then download the latest GitHub files', 'Using the current `update.py`, download the latest GitHub files', 'The file to open `--file file_name.berf[x]`']
# ln: 1795
# ln: 1423
for prg, text in translatable:
if text not in remove:
translate_dict['en'][text] = text
for text in add:
translate_dict['en'][text] = text
print(translate_dict)
text = test_str
for trans in translate_dict['en'].values():
r_trans = rf"(text|label)=('''|'|\")({trans})('''|'|\")"
text = re.sub(r_trans, r"\1=_[\2\3\4]", text)
# Manual Replacements
lines = [
"start += '<p><b>Final Volume: </b>{volume} Litres</p>'.format(volume=self.volume.get())",
"start += '<p><b>Original Gravity: </b>{og}</p>'.format(og=round(self.og, 1))",
"start += '<p><b>Final Gravity: </b>{fg}</p>'.format(fg=round(self.fg, 1))",
"start += '<p><b>Alcohol Content: </b>{abv}% ABV</p>'.format(abv=round(self.abv, 1))",
"start += '<p><b>Mash Efficiency: </b>{efficiency}</p>'.format(efficiency=brew_data.constants['Efficiency']*100)",
"start += '<p><b>Bitterness: </b>{bitterness} IBU</p>'.format(bitterness=round(self.ibu))",
"start += '<p><b>Colour: </b>{colour} EBC</p>'.format(colour=round(self.colour, 1))",
"start += '''<hr><h2>Notes</h2>\n{notes}'''.format(notes=notes) if len(notes) >= 1 else ''",
"start += '''<hr><h2>Notes</h2>\n<p>{notes}</p>'''.format(notes=notes.replace('\n', '<br>')) if len(notes) >= 1 else ''",
"self.calc_lbl.insert('end', '''Efficiency: {efficiency}%{enter}Final Gravity: {final_gravity}{enter}Alcohol (ABV): {abv}{enter}Colour: {colour}EBC{enter}Mash Liquor: {mash_liquor}L{enter}IBU:GU: {ibu_gu}'''.format("
]
line_replacement = [
"start += '<p><b>{rep} </b>{volume} Litres</p>'.format(volume=self.volume.get(), rep=_['Final Volume:'])",
"start += '<p><b>{rep} </b>{og}</p>'.format(og=round(self.og, 1), rep=_['Original Gravity:'])",
"start += '<p><b>{rep} </b>{fg}</p>'.format(fg=round(self.fg, 1), rep=_['Final Gravity:'])",
"start += '<p><b>{rep} </b>{abv}% ABV</p>'.format(abv=round(self.abv, 1), rep=_['Alcohol Content:'])",
"start += '<p><b>{rep} </b>{efficiency}</p>'.format(efficiency=brew_data.constants['Efficiency']*100, rep=_['Mash Efficiency:'])",
"start += '<p><b>{rep} </b>{bitterness} IBU</p>'.format(bitterness=round(self.ibu), rep=_['Bitterness:'])",
"start += '<p><b>{rep} </b>{colour} EBC</p>'.format(colour=round(self.colour, 1), rep=_['Colour:'])",
"start += '''<hr><h2>{rep}</h2>\n{notes}'''.format(notes=notes, rep=_['Notes:']) if len(notes) >= 1 else ''",
"start += '''<hr><h2>{rep}</h2>\n<p>{notes}</p>'''.format(notes=notes.replace('\n', '<br>'), rep=_['Notes:']) if len(notes) >= 1 else ''",
"self.calc_lbl.insert('end', '''{rep1} {efficiency}%{enter}{rep2} {final_gravity}{enter}{rep3} {abv}{enter}{rep4} {colour}EBC{enter}{rep5} {mash_liquor}L{enter}IBU:GU: {ibu_gu}'''.format(rep1=_['Efficiency:'], rep2=_['Final Gravity:'], rep3=_['Alcohol (ABV):'], rep4=_['Colour:'], rep5=_['Mash Liquor:'],"
]
for idx, line in enumerate(lines):
text = text.replace(line, line_replacement[idx])
# print(text)
with open('beer_engine_lang.py', 'w', encoding='utf8') as f:
f.write(text)
And yes I know, before anyone comments on this, I know that this is bad code, I mean for a start, why did I make a list of regexes
, when I literally have a regex that does the exact same job a couple of lines later??? Well, bad programming obviously! But it works, so that's what I care about, and it is not a critical bit of software, so it can be as shoddy as I like :).
So basically, I fully used regexes to substitute and generate this JSON file.
Have an amazing day!
Installing and Setting Up Wheeler's Wort Works
Wheeler's Wort Works Starting Guide
File types in Wheeler's Wort Works
An Advanced Guide to the Engine Room
An Advanced Guide to the Hop/Grist/Yeast Editors
An Advanced Guide to the Defaults Editor
An Advanced Guide to the Experimental Attenuation Tab
A Simple Guide for the Notes Area
How I programmed multi language support in Wheeler's Wort Works
Adding support for your language