Index: django/contrib/localflavor/be/be_regions.py
===================================================================
--- django/contrib/localflavor/be/be_regions.py	(revision 0)
+++ django/contrib/localflavor/be/be_regions.py	(revision 0)
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+from django.utils.translation import ugettext_lazy as _
+
+# ISO codes
+REGION_CHOICES = (
+    ('BRU', _('Brussels Capital Region')),
+    ('VLG', _('Flemish Region')),
+    ('WAL', _('Wallonia'))
+)
+
Index: django/contrib/localflavor/be/be_provinces.py
===================================================================
--- django/contrib/localflavor/be/be_provinces.py	(revision 0)
+++ django/contrib/localflavor/be/be_provinces.py	(revision 0)
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+from django.utils.translation import ugettext_lazy as _
+
+# ISO codes
+PROVINCE_CHOICES = (
+    ('VAN', _('Antwerp')),
+    ('BRU', _('Brussels')),
+    ('VOV', _('East Flanders')),
+    ('VBR', _('Flemish Brabant')),
+    ('WHT', _('Hainaut')),
+    ('WLG', _('Liege')),
+    ('VLI', _('Limburg')),
+    ('WLX', _('Luxembourg')),
+    ('WNA', _('Namur')),
+    ('WBR', _('Walloon Brabant')),
+    ('VWV', _('West Flanders'))
+)
+
Index: django/contrib/localflavor/be/__init__.py
===================================================================
Index: django/contrib/localflavor/be/forms.py
===================================================================
--- django/contrib/localflavor/be/forms.py	(revision 0)
+++ django/contrib/localflavor/be/forms.py	(revision 0)
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+"""
+Belgium-specific Form helpers
+"""
+
+from django.core.validators import EMPTY_VALUES
+from django.forms import ValidationError
+from django.forms.fields import RegexField, Select
+from django.utils.translation import ugettext_lazy as _
+import re
+
+class BEPostalCodeField(RegexField):
+    """
+    A form field that validates its input as a belgium postal code.
+    
+    Belgium postal code is a 4 digits string. The first digit indicates
+    the province (except for the 3ddd numbers that are shared by the
+    eastern part of Flemish Brabant and Limburg and the and 1ddd that
+    are shared by the Brussels Capital Region, the western part of
+    Flemish Brabant and Walloon Brabant)
+    """
+    default_error_messages = {
+        'invalid': _('Enter a valid postal code in the range and \
+            format 1XXX - 9XXX.'),
+    }
+
+    def __init__(self, *args, **kwargs):
+        super(BEPostalCodeField, self).__init__(
+                r'^[1-9]\d{3}$',
+                max_length=None, min_length=None, *args, **kwargs)
+
+class BEPhoneNumberField(RegexField):
+    """
+    A form field that validates its input as a belgium phone number.
+
+    Landlines have a seven-digit subscriber number and a one-digit area code,
+    while smaller cities have a six-digit subscriber number and a two-digit 
+    area code. Cell phones have a six-digit subscriber number and a two-digit 
+    area code preceeded by the number 4.
+    0d ddd dd dd, 0d/ddd.dd.dd, 0dddddddd - dialling a bigger city
+    0dd dd dd dd, 0dd/dd.dd.dd, 0dddddddd - dialling a smaller city
+    04dd ddd dd dd, 04dd/ddd.dd.dd, 04ddddddddd - dialling a mobile number
+    """
+    default_error_messages = {
+        'invalid': _('Enter a valid phone number in one of the formats \
+0x xxx xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, \
+04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.'),
+    }
+
+    def __init__(self, *args, **kwargs):
+        super(BEPhoneNumberField, self).__init__(r'^[0]\d{1}[/. ]?\d{3}[. ]\d{2}[. ]?\d{2}$|^[0]\d{2}[/. ]?\d{2}[. ]?\d{2}[. ]?\d{2}$|^[0][4]\d{2}[/. ]?\d{2}[. ]?\d{2}[. ]?\d{2}$',
+            max_length=None, min_length=None, *args, **kwargs)
+
+class BERegionSelect(Select):
+    """
+    A Select widget that uses a list of belgium regions as its choices.
+    """
+    def __init__(self, attrs=None):
+        from be_regions import REGION_CHOICES
+        super(BERegionSelect, self).__init__(attrs, choices=REGION_CHOICES)
+
+class BEProvinceSelect(Select):
+    """
+    A Select widget that uses a list of belgium provinces as its choices.
+    """
+    def __init__(self, attrs=None):
+        from be_provinces import PROVINCE_CHOICES
+        super(BEProvinceSelect, self).__init__(attrs, choices=PROVINCE_CHOICES)
+
Index: tests/regressiontests/forms/tests.py
===================================================================
--- tests/regressiontests/forms/tests.py	(revision 13957)
+++ tests/regressiontests/forms/tests.py	(working copy)
@@ -5,6 +5,7 @@
 from localflavor.ar import tests as localflavor_ar_tests
 from localflavor.at import tests as localflavor_at_tests
 from localflavor.au import tests as localflavor_au_tests
+from localflavor.be import tests as localflavor_be_tests
 from localflavor.br import tests as localflavor_br_tests
 from localflavor.ca import tests as localflavor_ca_tests
 from localflavor.ch import tests as localflavor_ch_tests
@@ -50,6 +51,7 @@
     'localflavor_ar_tests': localflavor_ar_tests,
     'localflavor_at_tests': localflavor_at_tests,
     'localflavor_au_tests': localflavor_au_tests,
+    'localflavor_be_tests': localflavor_be_tests,
     'localflavor_br_tests': localflavor_br_tests,
     'localflavor_ca_tests': localflavor_ca_tests,
     'localflavor_ch_tests': localflavor_ch_tests,
Index: tests/regressiontests/forms/localflavor/be.py
===================================================================
--- tests/regressiontests/forms/localflavor/be.py	(revision 0)
+++ tests/regressiontests/forms/localflavor/be.py	(revision 0)
@@ -0,0 +1,190 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ BE form fields.
+
+tests = r"""
+# BEPostalCodeField ##############################################################
+
+BEPostalCodeField validates that data is a four-digit belgium postal code following the regex ^[1-9](/d){3}$.
+>>> from django.contrib.localflavor.be.forms import BEPostalCodeField
+>>> f = BEPostalCodeField()
+>>> f.clean('1451')
+u'1451'
+>>> f.clean('2540')
+u'2540'
+>>> f.clean('0287')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('14309')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('873')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('35 74')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('859A')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = BEPostalCodeField(required=False)
+>>> f.clean('1451')
+u'1451'
+>>> f.clean('2540')
+u'2540'
+>>> f.clean('0287')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('14309')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('873')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('35 74')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('859A')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid postal code in the range and format 1XXX - 9XXX.']
+>>> f.clean('')
+u''
+
+# BEPhoneNumberField ##############################################################
+
+BEPhoneNumberField validates that data follows: Landlines have a seven-digit subscriber number and a one-digit area code, while smaller cities have a six-digit subscriber number and a two-digit area code. Cell phones have a six-digit subscriber number and a two-digit area code preceeded by the number 4.
+0d ddd dd dd, 0d/ddd.dd.dd - dialling a bigger city
+0dd dd dd dd, 0dd/dd.dd.dd - dialling a smaller city
+04dd dd dd dd, 04dd/dd.dd.dd - dialling a mobile number
+
+>>> from django.contrib.localflavor.be.forms import BEPhoneNumberField
+>>> f = BEPhoneNumberField()
+>>> f.clean('01 234 56 78')
+u'01 234 56 78'
+>>> f.clean('01/234.56.78')
+u'01/234.56.78'
+>>> f.clean('012 34 56 78')
+u'012 34 56 78'
+>>> f.clean('012/34.56.78')
+u'012/34.56.78'
+>>> f.clean('0412 34 56 78')
+u'0412 34 56 78'
+>>> f.clean('0412/34.56.78')
+u'0412/34.56.78'
+>>> f.clean('012345678')
+u'012345678'
+>>> f.clean('0412345678')
+u'0412345678'
+>>> f.clean('01234567')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('12/345.67.89')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('012/345.678.90')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('012/34.56.789')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('0123/45.67.89')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('012/345 678 90')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('012/34 56 789')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = BEPhoneNumberField(required=False)
+>>> f.clean('01 234 56 78')
+u'01 234 56 78'
+>>> f.clean('01/234.56.78')
+u'01/234.56.78'
+>>> f.clean('012 34 56 78')
+u'012 34 56 78'
+>>> f.clean('012/34.56.78')
+u'012/34.56.78'
+>>> f.clean('0412 34 56 78')
+u'0412 34 56 78'
+>>> f.clean('0412/34.56.78')
+u'0412/34.56.78'
+>>> f.clean('012345678')
+u'012345678'
+>>> f.clean('0412345678')
+u'0412345678'
+>>> f.clean('12345678')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('12/345.67.89')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('012/345.678.90')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('012/34.56.789')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('0123/45.67.89')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('012/345 678 90')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('012/34 56 789')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid phone number in one of the formats 0x xxx   xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx, 0xx/xx.xx.xx, 04xx/xx.xx.xx, 0xxxxxxxx, 04xxxxxxxx.']
+>>> f.clean('')
+u''
+
+# BERegionSelect ##############################################################
+
+BERegionSelect is a Select widget that uses a list of belgium regions as its choices.
+>>> from django.contrib.localflavor.be.forms import BERegionSelect
+>>> w = BERegionSelect()
+>>> w.render('regions', 'VLG')
+u'<select name="regions">\n<option value="BRU">Brussels Capital Region</option>\n<option value="VLG" selected="selected">Flemish Region</option>\n<option value="WAL">Wallonia</option>\n</select>'
+
+# BEProvinceSelect ##############################################################
+
+BEProvinceSelect is a Select widget that uses a list of Belgium provinces as its choices.
+>>> from django.contrib.localflavor.be.forms import BEProvinceSelect
+>>> w = BEProvinceSelect()
+>>> w.render('provinces', 'WLG')
+u'<select name="provinces">\n<option value="VAN">Antwerp</option>\n<option value="BRU">Brussels</option>\n<option value="VOV">East Flanders</option>\n<option value="VBR">Flemish Brabant</option>\n<option value="WHT">Hainaut</option>\n<option value="WLG" selected="selected">Liege</option>\n<option value="VLI">Limburg</option>\n<option value="WLX">Luxembourg</option>\n<option value="WNA">Namur</option>\n<option value="WBR">Walloon Brabant</option>\n<option value="VWV">West Flanders</option>\n</select>'
+
+"""
+
Index: docs/ref/contrib/localflavor.txt
===================================================================
--- docs/ref/contrib/localflavor.txt	(revision 13957)
+++ docs/ref/contrib/localflavor.txt	(working copy)
@@ -39,6 +39,7 @@
     * Argentina_
     * Australia_
     * Austria_
+    * Belgium_
     * Brazil_
     * Canada_
     * Chile_
@@ -85,6 +86,7 @@
 .. _Argentina: `Argentina (ar)`_
 .. _Australia: `Australia (au)`_
 .. _Austria: `Austria (at)`_
+.. _Belgium: `Belgium (be)`_
 .. _Brazil: `Brazil (br)`_
 .. _Canada: `Canada (ca)`_
 .. _Chile: `Chile (cl)`_
@@ -182,6 +184,30 @@
 
     A form field that validates its input as an Austrian social security number.
 
+Belgium (``be``)
+===============
+
+.. class:: be.forms.BEPhoneNumberField
+
+    A form field that validates input as a Belgium phone number, with one of 
+    the formats 0x xxx xx xx, 0xx xx xx xx, 04xx xx xx xx, 0x/xxx.xx.xx,
+    0xx/xx.xx.xx, 04xx/xx.xx.xx.
+
+.. class:: be.forms.BEPostalCodeField
+
+    A form field that validates input as a Belgium postal code, in the range
+    and format 1XXX-9XXX.
+
+.. class:: be.forms.BEProvinceSelect
+
+    A ``Select`` widget that uses a list of Belgium provinces as its
+    choices.
+
+.. class:: be.forms.BERegionSelect
+
+    A ``Select`` widget that uses a list of Belgium regions as its
+    choices.
+
 Brazil (``br``)
 ===============
 
