I’ve made a few Badge classes in Django, each containing some sort of description in a string variable:
"You get this badge because you've runned %d meters in %d minutes"
"You get this badge because you've killed %d monsters of the type %s"
etc. And the classes also have a function get_description(badge_level_requirements), so in the templates it will be called together with a list to assemble the string for a specific user:
class RunnerBadge(Badge):
des=ugettext_lazy("You get this badge because you've runned %d meters in %d minutes")
def get_description(cls,badge_level_requirements):
return cls.des%badge_level_requirements
And I’ve stored the requirements lists in the database without any argument names already 🙁 As shown in the examples, different classes have different numbers of values to fill in the string, the values mean different things as well. So I can’t really name the arguments.
However, if I want to internationalize these strings, there’ll be errors: 'msgid' format string with unnamed arguments cannot be properly localized And the language file cannot be generated for this matter.
Is there a way to bypass this error?
Update
I’ve come across this method for bypassing the error without changing database.
In database, the level requirements are stored in a text field in the format of dict:
#Requirment of Runner's badge
"{'gold':(100,10),'silver':(50,5),'bronze':(25,2)}"
And in class definition, mannually add argument names as ‘arg_0’,’arg_1’… to descriptions. The get_description method is changed to pre-process the data before used for filling description strings.
class RunnersBadge(Badge):
requirements=#get the previous dict from database
description="You get this badge because you've runned %(arg_0)d meters in %(arg_1)d minutes"
@classmethod
def get_description(cls,level):
'''
This is actually a method of parent class Badge
level is either 'gold','silver' or 'bronze'
'''
dic={}
try:
for (num,val) in enumerate(cls.requirements[level]):
dic['arg_'+str(num)]=val
except TypeError:
dic['arg_0']=cls.requirements[level]
return cls.description%dic
This method keeps most of the current structure (logic and database). And the translator just need to take care of the words’ placement.
like in code, variable names should be meaningful within their context, ‘meter_count’ and ‘minute_count’ are explicit, compared to ‘arg_0’ and ‘arg_1’ which are meaningless
use standard translation in python code, it is less error prone and is recognized by the amazingly useful makemessages command
use use named-string interpolation (e.g.,
%(day)s) instead of positional interpolation (e.g.,%sor%d) whenever you have more than a single parameter, because the order of parameters can change depending on the language. I.e. germanic and latin languages inverse the noun/adjective order, dates are displayed differently depending on the language, etc, etc …use ran instead of runned, double check the syntactical validity of your english translation strings
This:
Becomes: