Ticket #4030: 4030_language_info_v2_r10639.diff
File 4030_language_info_v2_r10639.diff, 21.3 KB (added by , 16 years ago) |
---|
-
new file django/bin/make-language-info.py
diff --git a/django/bin/make-language-info.py b/django/bin/make-language-info.py new file mode 100644 index 0000000..707f181
- + 1 #!/usr/bin/env python 2 3 LANGUAGE_INFO_PY_FILE = 'django/conf/language_info.py' 4 5 # Need to ensure that the i18n framework is enabled 6 from django.conf import settings 7 settings.configure(USE_I18N = True) 8 9 TEMPLATE = """\ 10 # This file was generated with django/bin/make-language-info.py and it is not 11 # recommended to edit it by hand. For new translations, compile the new .po 12 # files and edit the LANGUAGES setting, and finally re-run 13 # django/bin/make-language-info.py to generate this file. 14 15 language_info = { 16 %s 17 } 18 """ 19 20 def make_language_info(target_path): 21 print 'Writing language information to\n%s' % target_path 22 # Create a dummy language_info.py file to make sure we can import the 23 # translation module. 24 file(target_path, 'w').write(TEMPLATE % '') 25 from django.utils import translation 26 from pprint import pformat 27 language_info = {} 28 for code, name in settings.LANGUAGES: 29 translation.activate(code) 30 language_info[code] = {"language_code": code, 31 "name": name, 32 "name_local": translation.ugettext(name), 33 "bidi": code in settings.LANGUAGES_BIDI} 34 file(target_path, 'w').write(TEMPLATE % pformat(language_info)[1:-1]) 35 # Because the timestamps of the dummy .pyc and real .py may fall on the 36 # same second, we must enforce compilation. 37 import py_compile 38 py_compile.compile(target_path) 39 print 'Done.' 40 41 42 if __name__ == "__main__": 43 from os.path import join, dirname, abspath 44 path = abspath(join(dirname(__file__), '..', '..', LANGUAGE_INFO_PY_FILE)) 45 make_language_info(path) -
new file django/conf/language_info.py
diff --git a/django/conf/language_info.py b/django/conf/language_info.py new file mode 100644 index 0000000..794b4ee
- + 1 # This file was generated with django/bin/make-language-info.py and it is not 2 # recommended to edit it by hand. For new translations, compile the new .po 3 # files and edit the LANGUAGES setting, and finally re-run 4 # django/bin/make-language-info.py to generate this file. 5 6 language_info = { 7 'ar': {'bidi': True, 8 'language_code': 'ar', 9 'name': 'Arabic', 10 'name_local': u'\u0627\u0644\u0639\u0631\u0628\u064a\u0651\u0629'}, 11 'bg': {'bidi': False, 12 'language_code': 'bg', 13 'name': 'Bulgarian', 14 'name_local': u'\u0431\u044a\u043b\u0433\u0430\u0440\u0441\u043a\u0438'}, 15 'bn': {'bidi': False, 16 'language_code': 'bn', 17 'name': 'Bengali', 18 'name_local': u'\u09ac\u09be\u0982\u09b2\u09be'}, 19 'ca': {'bidi': False, 20 'language_code': 'ca', 21 'name': 'Catalan', 22 'name_local': u'catal\xe0'}, 23 'cs': {'bidi': False, 24 'language_code': 'cs', 25 'name': 'Czech', 26 'name_local': u'\u010desky'}, 27 'cy': {'bidi': False, 28 'language_code': 'cy', 29 'name': 'Welsh', 30 'name_local': u'Cymraeg'}, 31 'da': {'bidi': False, 32 'language_code': 'da', 33 'name': 'Danish', 34 'name_local': u'Dansk'}, 35 'de': {'bidi': False, 36 'language_code': 'de', 37 'name': 'German', 38 'name_local': u'Deutsch'}, 39 'el': {'bidi': False, 40 'language_code': 'el', 41 'name': 'Greek', 42 'name_local': u'\u0395\u03bb\u03bb\u03b7\u03bd\u03b9\u03ba\u03ac'}, 43 'en': {'bidi': False, 44 'language_code': 'en', 45 'name': 'English', 46 'name_local': u'English'}, 47 'es': {'bidi': False, 48 'language_code': 'es', 49 'name': 'Spanish', 50 'name_local': u'espa\xf1ol'}, 51 'es-ar': {'bidi': False, 52 'language_code': 'es-ar', 53 'name': 'Argentinean Spanish', 54 'name_local': u'espa\xf1ol de Argentina'}, 55 'et': {'bidi': False, 56 'language_code': 'et', 57 'name': 'Estonian', 58 'name_local': u'eesti'}, 59 'eu': {'bidi': False, 60 'language_code': 'eu', 61 'name': 'Basque', 62 'name_local': u'Basque'}, 63 'fa': {'bidi': True, 64 'language_code': 'fa', 65 'name': 'Persian', 66 'name_local': u'\u0641\u0627\u0631\u0633\u06cc'}, 67 'fi': {'bidi': False, 68 'language_code': 'fi', 69 'name': 'Finnish', 70 'name_local': u'suomi'}, 71 'fr': {'bidi': False, 72 'language_code': 'fr', 73 'name': 'French', 74 'name_local': u'Fran\xe7ais'}, 75 'ga': {'bidi': False, 76 'language_code': 'ga', 77 'name': 'Irish', 78 'name_local': u'Gaeilge'}, 79 'gl': {'bidi': False, 80 'language_code': 'gl', 81 'name': 'Galician', 82 'name_local': u'galego'}, 83 'he': {'bidi': True, 84 'language_code': 'he', 85 'name': 'Hebrew', 86 'name_local': u'\u05e2\u05d1\u05e8\u05d9\u05ea'}, 87 'hi': {'bidi': False, 88 'language_code': 'hi', 89 'name': 'Hindi', 90 'name_local': u'Hindi'}, 91 'hr': {'bidi': False, 92 'language_code': 'hr', 93 'name': 'Croatian', 94 'name_local': u'Hrvatski'}, 95 'hu': {'bidi': False, 96 'language_code': 'hu', 97 'name': 'Hungarian', 98 'name_local': u'Magyar'}, 99 'is': {'bidi': False, 100 'language_code': 'is', 101 'name': 'Icelandic', 102 'name_local': u'\xcdslenska'}, 103 'it': {'bidi': False, 104 'language_code': 'it', 105 'name': 'Italian', 106 'name_local': u'italiano'}, 107 'ja': {'bidi': False, 108 'language_code': 'ja', 109 'name': 'Japanese', 110 'name_local': u'\u65e5\u672c\u8a9e'}, 111 'ka': {'bidi': False, 112 'language_code': 'ka', 113 'name': 'Georgian', 114 'name_local': u'\u10e5\u10d0\u10e0\u10d7\u10e3\u10da\u10d8'}, 115 'km': {'bidi': False, 116 'language_code': 'km', 117 'name': 'Khmer', 118 'name_local': u'Khmer'}, 119 'kn': {'bidi': False, 120 'language_code': 'kn', 121 'name': 'Kannada', 122 'name_local': u'Kannada'}, 123 'ko': {'bidi': False, 124 'language_code': 'ko', 125 'name': 'Korean', 126 'name_local': u'\ud55c\uad6d\uc5b4'}, 127 'lt': {'bidi': False, 128 'language_code': 'lt', 129 'name': 'Lithuanian', 130 'name_local': u'Lithuanian'}, 131 'lv': {'bidi': False, 132 'language_code': 'lv', 133 'name': 'Latvian', 134 'name_local': u'Latvie\u0161u'}, 135 'mk': {'bidi': False, 136 'language_code': 'mk', 137 'name': 'Macedonian', 138 'name_local': u'\u041c\u0430\u043a\u0435\u0434\u043e\u043d\u0441\u043a\u0438'}, 139 'nl': {'bidi': False, 140 'language_code': 'nl', 141 'name': 'Dutch', 142 'name_local': u'Nederlands'}, 143 'no': {'bidi': False, 144 'language_code': 'no', 145 'name': 'Norwegian', 146 'name_local': u'Norsk'}, 147 'pl': {'bidi': False, 148 'language_code': 'pl', 149 'name': 'Polish', 150 'name_local': u'polski'}, 151 'pt': {'bidi': False, 152 'language_code': 'pt', 153 'name': 'Portuguese', 154 'name_local': u'Portuguese'}, 155 'pt-br': {'bidi': False, 156 'language_code': 'pt-br', 157 'name': 'Brazilian Portuguese', 158 'name_local': u'Portugu\xeas Brasileiro'}, 159 'ro': {'bidi': False, 160 'language_code': 'ro', 161 'name': 'Romanian', 162 'name_local': u'Romana'}, 163 'ru': {'bidi': False, 164 'language_code': 'ru', 165 'name': 'Russian', 166 'name_local': u'\u0420\u0443\u0441\u0441\u043a\u0438\u0439'}, 167 'sk': {'bidi': False, 168 'language_code': 'sk', 169 'name': 'Slovak', 170 'name_local': u'slovensk\xfd'}, 171 'sl': {'bidi': False, 172 'language_code': 'sl', 173 'name': 'Slovenian', 174 'name_local': u'Sloven\u0161\u010dina'}, 175 'sr': {'bidi': False, 176 'language_code': 'sr', 177 'name': 'Serbian', 178 'name_local': u'\u0421\u0440\u043f\u0441\u043a\u0438'}, 179 'sv': {'bidi': False, 180 'language_code': 'sv', 181 'name': 'Swedish', 182 'name_local': u'Svenska'}, 183 'ta': {'bidi': False, 184 'language_code': 'ta', 185 'name': 'Tamil', 186 'name_local': u'\u0ba4\u0bae\u0bbf\u0bb4\u0bcd'}, 187 'te': {'bidi': False, 188 'language_code': 'te', 189 'name': 'Telugu', 190 'name_local': u'\u0c24\u0c46\u0c32\u0c41\u0c17\u0c41'}, 191 'th': {'bidi': False, 192 'language_code': 'th', 193 'name': 'Thai', 194 'name_local': u'Thai'}, 195 'tr': {'bidi': False, 196 'language_code': 'tr', 197 'name': 'Turkish', 198 'name_local': u'T\xfcrk\xe7e'}, 199 'uk': {'bidi': False, 200 'language_code': 'uk', 201 'name': 'Ukrainian', 202 'name_local': u'\u0423\u043a\u0440\u0430\u0457\u043d\u0441\u044c\u043a\u0430'}, 203 'zh-cn': {'bidi': False, 204 'language_code': 'zh-cn', 205 'name': 'Simplified Chinese', 206 'name_local': u'\u7b80\u4f53\u4e2d\u6587'}, 207 'zh-tw': {'bidi': False, 208 'language_code': 'zh-tw', 209 'name': 'Traditional Chinese', 210 'name_local': u'\u7e41\u9ad4\u4e2d\u6587'} 211 } -
django/templatetags/i18n.py
diff --git a/django/templatetags/i18n.py b/django/templatetags/i18n.py index 0467433..b656b9d 100644
a b class GetAvailableLanguagesNode(Node): 17 17 context[self.variable] = [(k, translation.ugettext(v)) for k, v in settings.LANGUAGES] 18 18 return '' 19 19 20 class GetLanguageInfoNode(Node): 21 def __init__(self, lang_code, variable): 22 self.lang_code = Variable(lang_code) 23 self.variable = variable 24 25 def render(self, context): 26 lang_code = self.lang_code.resolve(context) 27 context[self.variable] = translation.get_language_info(lang_code) 28 return '' 29 30 class GetLanguageInfoListNode(Node): 31 def __init__(self, languages, variable): 32 self.languages = Variable(languages) 33 self.variable = variable 34 35 def get_language_info(self, language): 36 # ``language`` is either a language code string or a sequence with the 37 # language code as its first item 38 if len(language[0]) > 1: 39 return translation.get_language_info(language[0]) 40 else: 41 return translation.get_language_info(str(language)) 42 43 def render(self, context): 44 languages = self.languages.resolve(context) 45 context[self.variable] = [self.get_language_info(l) for l in languages] 46 return '' 47 20 48 class GetCurrentLanguageNode(Node): 21 49 def __init__(self, variable): 22 50 self.variable = variable … … def do_get_available_languages(parser, token): 107 135 raise TemplateSyntaxError, "'get_available_languages' requires 'as variable' (got %r)" % args 108 136 return GetAvailableLanguagesNode(args[2]) 109 137 138 def do_get_language_info(parser, token): 139 """ 140 This will store the language information dictionary for the given language 141 code in a context variable. 142 143 Usage:: 144 145 {% get_language_info for language_code as l %} 146 {{ l.language_code }} 147 {{ l.name }} 148 {{ l.name_local }} 149 {{ l.bidi|yesno:"bi-directional,uni-directional" }} 150 """ 151 args = token.contents.split() 152 if len(args) != 5 or args[1] != 'for' or args[3] != 'as': 153 raise TemplateSyntaxError, "'%s' requires 'for string as variable' (got %r)" % (args[0], args[1:]) 154 return GetLanguageInfoNode(args[2], args[4]) 155 156 def do_get_language_info_list(parser, token): 157 """ 158 This will store a list of language information dictionaries for the given 159 language codes in a context variable. The language codes can be specified 160 ither as a list of strings or a settings.LANGUAGES style tuple (or any 161 sequence of sequences whose first items are language codes). 162 163 Usage:: 164 165 {% get_language_info_list for LANGUAGES as langs %} 166 {% for l in langs %} 167 {{ l.language_code }} 168 {{ l.name }} 169 {{ l.name_local }} 170 {{ l.bidi|yesno:"bi-directional,uni-directional" }} 171 {% endfor %} 172 """ 173 args = token.contents.split() 174 if len(args) != 5 or args[1] != 'for' or args[3] != 'as': 175 raise TemplateSyntaxError, "'%s' requires 'for sequence as variable' (got %r)" % (args[0], args[1:]) 176 return GetLanguageInfoListNode(args[2], args[4]) 177 178 def language_name(lang_code): 179 return translation.get_language_info(lang_code)['name'] 180 181 def language_name_local(lang_code): 182 return translation.get_language_info(lang_code)['name_local'] 183 184 def language_bidi(lang_code): 185 return translation.get_language_info(lang_code)['bidi'] 186 110 187 def do_get_current_language(parser, token): 111 188 """ 112 189 This will store the current language in the context. … … def do_block_translate(parser, token): 253 330 counter) 254 331 255 332 register.tag('get_available_languages', do_get_available_languages) 333 register.tag('get_language_info', do_get_language_info) 334 register.tag('get_language_info_list', do_get_language_info_list) 256 335 register.tag('get_current_language', do_get_current_language) 257 336 register.tag('get_current_language_bidi', do_get_current_language_bidi) 258 337 register.tag('trans', do_translate) 259 338 register.tag('blocktrans', do_block_translate) 339 340 register.filter(language_name) 341 register.filter(language_name_local) 342 register.filter(language_bidi) -
django/utils/translation/__init__.py
diff --git a/django/utils/translation/__init__.py b/django/utils/translation/__init__.py index c0a0df9..a942fe2 100644
a b Internationalization support. 3 3 """ 4 4 from django.utils.functional import lazy 5 5 from django.utils.encoding import force_unicode 6 try: 7 from django.conf.language_info import language_info 8 except ImportError: 9 raise ImportError("Module django.conf.language_info not found. Run django/bin/make-language-info.py to generate it.") 6 10 7 11 __all__ = ['gettext', 'gettext_noop', 'gettext_lazy', 'ngettext', 8 12 'ngettext_lazy', 'string_concat', 'activate', 'deactivate', … … def string_concat(*strings): 109 113 """ 110 114 return u''.join([force_unicode(s) for s in strings]) 111 115 string_concat = lazy(string_concat, unicode) 116 117 def get_language_info(lang_code): 118 try: 119 return language_info[lang_code] 120 except KeyError: 121 raise KeyError("Unknown language code %r. If you have added a new translation, remember to add the language to the LANGUAGES setting and update the django/conf/language_info.py file by running django/bin/make-language-info.py." % lang_code) -
docs/topics/i18n.txt
diff --git a/docs/topics/i18n.txt b/docs/topics/i18n.txt index 140adce..24b12fb 100644
a b in ``request.LANGUAGE_CODE``. 726 726 727 727 .. _translations-in-your-own-projects: 728 728 729 Local names of languages 730 ======================== 731 732 The ``get_language_info()`` function provides detailed information about 733 languages:: 734 735 >>> form django.utils.translation import get_language_info 736 >>> l = get_language_info('de') 737 >>> print l['name'], l['name_local'], l['bidi'] 738 German Deutsch False 739 740 The ``name`` and ``name_local`` attributes of the dictionary contain the name 741 of the language in English and the language itself, respectively. The ``bidi`` 742 attribute is True only for bi-directional languages. 743 744 In templates, you can use special template tags or filters to retrieve the same 745 information. To get information about a single language, use the 746 ``{% get_language_info %}`` tag:: 747 748 {% get_language_info for LANGUAGE_CODE as lang %} 749 {% get_language_info for "pl" as lang %} 750 751 You can then access the information:: 752 753 Language code: {{ lang.language_code }}<br /> 754 Name of language: {{ lang.name_local }}<br /> 755 Name in English: {{ lang.name }}<br /> 756 Bi-directional: {{ lang.bidi }} 757 758 You can also use the ``{% get_language_info_list %}`` template tag to retrieve 759 information for a list of languages (e.g. active languages as specified in 760 ``settings.LANGUAGES``). See `The set_language redirect view`_ for an example 761 of how to display a language selector using ``{% get_language_info_list %}``. 762 763 In addition to ``settings.LANGUAGES`` style nested tuples, 764 ``{% get_language_info_list %}`` supports simple lists of language codes. If 765 you do this in your view:: 766 767 return render_to_response('mytemplate.html', 768 {'available_languages': ['en', 'es', 'fr']}, 769 RequestContext(request)) 770 771 you can iterate those languages in the template:: 772 773 {% get_language_info_list available_languages %} 774 {% for l in available_languages %} ... {% endfor %} 775 776 There are also simple filters available for convenience: 777 778 * ``{{ LANGUAGE_CODE|language_name }}`` ("German") 779 * ``{{ LANGUAGE_CODE|language_name_local }}`` ("Deutsch") 780 * ``{{ LANGUAGE_CODE|bidi }}`` (False) 781 782 The source of the language information is the ``django.conf.language_info`` 783 module. If you add a new translation, you should run the 784 ``django/bin/make-language-info.py`` script to insert the information for the 785 added language. 786 729 787 Using translations in your own projects 730 788 ======================================= 731 789 … … algorithm: 817 875 * If that's empty -- say, if a user's browser suppresses that header -- 818 876 then the user will be redirected to ``/`` (the site root) as a fallback. 819 877 820 Here's example HTML template code: 878 Here's example HTML template code (see `Local names of languages`_ for more 879 information):: 821 880 822 881 .. code-block:: html+django 823 882 883 {% get_language_info_list for LANGUAGES as available_languages %} 824 884 <form action="/i18n/setlang/" method="post"> 825 <input name="next" type="hidden" value="/next/page/" /> 826 <select name="language"> 827 {% for lang in LANGUAGES %} 828 <option value="{{ lang.0 }}">{{ lang.1 }}</option> 829 {% endfor %} 830 </select> 831 <input type="submit" value="Go" /> 885 <input name="next" type="hidden" value="/next/page/" /> 886 <select name="language"> 887 {% for lang in available_languages %} 888 <option value="{{ lang.language_code }}" {% ifequal lang.language_code LANGUAGE_CODE %}selected{% endifequal %}> 889 {{ lang.name_local }} 890 </option> 891 {% endfor %} 892 </select> 893 <input type="submit" value="Go" /> 832 894 </form> 833 895 834 896 Translations and JavaScript -
new file tests/regressiontests/i18n/language_info.py
diff --git a/tests/regressiontests/i18n/language_info.py b/tests/regressiontests/i18n/language_info.py new file mode 100644 index 0000000..b5a1a3e
- + 1 tests = """ 2 >>> from django.utils.translation import get_language_info 3 >>> from pprint import pprint 4 >>> pprint(get_language_info('de')) 5 {'bidi': False, 6 'language_code': 'de', 7 'name': 'German', 8 'name_local': u'Deutsch'} 9 """ 10 tests = """ 11 >>> from django.utils.translation import get_language_info 12 >>> from pprint import pprint 13 >>> pprint(get_language_info('de')) 14 {'bidi': False, 15 'language_code': 'de', 16 'name': 'German', 17 'name_local': u'Deutsch'} 18 """ -
tests/regressiontests/i18n/tests.py
diff --git a/tests/regressiontests/i18n/tests.py b/tests/regressiontests/i18n/tests.py index 94e792c..81cfc1d 100644
a b 1 1 # coding: utf-8 2 import misc 2 import misc, language_info 3 3 4 4 regressions = ur""" 5 5 Format string interpolation should work with *_lazy objects. … … Password 68 68 69 69 __test__ = { 70 70 'regressions': regressions, 71 'language_info': language_info.tests, 71 72 'misc': misc.tests, 72 73 } -
tests/regressiontests/templates/tests.py
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index d740dbf..a60b83d 100644
a b class Templates(unittest.TestCase): 869 869 'i18n21': ('{% load i18n %}{% blocktrans %}{{ andrew }}{% endblocktrans %}', {'andrew': mark_safe('a & b')}, u'a & b'), 870 870 'i18n22': ('{% load i18n %}{% trans andrew %}', {'andrew': mark_safe('a & b')}, u'a & b'), 871 871 872 # retrieving language information 873 'i18n23': ('{% load i18n %}{% get_language_info for "de" as l %}{{ l.language_code }}: {{ l.name }}/{{ l.name_local }} bidi={{ l.bidi }}', {}, 'de: German/Deutsch bidi=False'), 874 'i18n24': ('{% load i18n %}{% get_language_info for LANGUAGE_CODE as l %}{{ l.language_code }}: {{ l.name }}/{{ l.name_local }} bidi={{ l.bidi }}', {'LANGUAGE_CODE': 'fi'}, 'fi: Finnish/suomi bidi=False'), 875 'i18n25': ('{% load i18n %}{% get_language_info_list for langcodes as langs %}{% for l in langs %}{{ l.language_code }}: {{ l.name }}/{{ l.name_local }} bidi={{ l.bidi }}; {% endfor %}', {'langcodes': ['it', 'no']}, u'it: Italian/italiano bidi=False; no: Norwegian/Norsk bidi=False; '), 876 'i18n26': ('{% load i18n %}{% get_language_info_list for langcodes as langs %}{% for l in langs %}{{ l.language_code }}: {{ l.name }}/{{ l.name_local }} bidi={{ l.bidi }}; {% endfor %}', {'langcodes': (('sl', 'Slovenian'), ('fa', 'Persian'))}, u'sl: Slovenian/Sloven\u0161\u010dina bidi=False; fa: Persian/\u0641\u0627\u0631\u0633\u06cc bidi=True; '), 877 'i18n27': ('{% load i18n %}{{ "hu"|language_name }} {{ "hu"|language_name_local }} {{ "hu"|language_bidi }}', {}, u'Hungarian Magyar False'), 878 'i18n28': ('{% load i18n %}{{ langcode|language_name }} {{ langcode|language_name_local }} {{ langcode|language_bidi }}', {'langcode': 'nl'}, u'Dutch Nederlands False'), 879 872 880 ### HANDLING OF TEMPLATE_STRING_IF_INVALID ################################### 873 881 874 882 'invalidstr01': ('{{ var|default:"Foo" }}', {}, ('Foo','INVALID')),