2016-04-07, 21:21
i18n (internationalization) in Python is usually easy, thanks to the gettext module.
However, once I started to develop addons for Kodi, I noticed addon i18n is quite hmm.. ugly.
Take a look at the following piece of code taken from the Kodi wiki:
Using string ids leads to unreadable code. Furthermore, development is hard because you need to jump between your code and the English/strings.po file every time you want to add a new localized string. I wasn't sure how to make gettext work with xbmc (i.e., keep using xbmcaddon.getLocalizedString), so I wrote a small script instead and it worked perfectly fine for me in the Meta video search addon.
Requirements:
Python, grep and polib are needed on your development machine.
Usage:
The script: (save as language.py)
Other:
However, once I started to develop addons for Kodi, I noticed addon i18n is quite hmm.. ugly.
Take a look at the following piece of code taken from the Kodi wiki:
Code:
import xbmcaddon
__settings__ = xbmcaddon.Addon(id='<your addons ID>')
__language__ = __settings__.getLocalizedString
__language__(30204) # this will return localized string from resources/language/<name_of_language>/strings.xml
Using string ids leads to unreadable code. Furthermore, development is hard because you need to jump between your code and the English/strings.po file every time you want to add a new localized string. I wasn't sure how to make gettext work with xbmc (i.e., keep using xbmcaddon.getLocalizedString), so I wrote a small script instead and it worked perfectly fine for me in the Meta video search addon.
Requirements:
Python, grep and polib are needed on your development machine.
- to install polib use pip (located in C:\Python27\Scripts\ on windows): Code:
pip install polib
- grep for windows is available here.
Usage:
- Save the script in the root folder of your addon as language.py.
- Make sure the root folder also contains a resources/language/English/strings.po file (can contain just metadata or even be empty)
- From your addon code use the following import line Code:
from language import get_string as _
- From your addon code don't use "Some text" or getLocalizedString(some_id) for localized strings, instead use Code:
_("Some text")
- Run the language.py script with python and it will self generate to reflect your code changes + add missing text entries to the main strings.po file.
The script: (save as language.py)
Code:
#! /usr/bin/python
__strings = {}
if __name__ == "__main__":
import polib
po = polib.pofile('resources/language/English/strings.po')
try:
import re
import subprocess
r = subprocess.check_output(["grep", "-hnr", "_([\'\"]", "."])
strings = re.compile("_\([\"'](.*?)[\"']\)", re.IGNORECASE).findall(r)
translated = [m.msgid.lower().replace("'", "\\'") for m in po]
missing = set([s for s in strings if s.lower() not in translated])
if missing:
ids_range = range(30000, 31000)
ids_reserved = [int(m.msgctxt[1:]) for m in po]
ids_available = [x for x in ids_range if x not in ids_reserved]
print "warning: missing translation for", missing
for text in missing:
id = ids_available.pop(0)
entry = polib.POEntry(
msgid=text,
msgstr=u'',
msgctxt="#{0}".format(id)
)
po.append(entry)
po.save('resources/language/English/strings.po')
except:
pass
content = []
with open(__file__, "r") as me:
content = me.readlines()
content = content[:content.index("#GENERATED\n")+1]
with open(__file__, 'w') as f:
f.writelines(content)
for m in po:
line = "__strings['{0}'] = {1}\n".format(m.msgid.lower().replace("'", "\\'"), m.msgctxt.replace('#', '').strip())
f.write(line)
else:
import xbmc, xbmcaddon
__language__ = xbmcaddon.Addon().getLocalizedString
def get_string(t):
id = __strings.get(t.lower())
if id:
return __language__(id)
xbmc.log("missing translation for " + t.lower())
return t
#setattr(__builtin__, '_', get_string)
#GENERATED
Other:
- You can register _() as a builtin and then your imports can be cleaner (just import language). To do that just un-comment the setattr line in the script.
- If you also use json-rpc in your addon check out another part I extracted from Meta last month: http://forum.kodi.tv/showthread.php?tid=264088