Index: /main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/paypal_countries.py
===================================================================
--- /main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/paypal_countries.py	(revision 12179)
+++ /main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/paypal_countries.py	(revision 12179)
@@ -0,0 +1,206 @@
+from waeup.ikoba.interfaces import MessageFactory as _
+from waeup.ikoba.interfaces import SimpleIkobaVocabulary
+
+
+#: A list of country codes as accepted by PayPal
+COUNTRIES = {
+    'AD': _('ANDORRA'),
+    'AE': _('UNITED ARAB EMIRATES'),
+    'AG': _('ANTIGUA AND BARBUDA'),
+    'AI': _('ANGUILLA'),
+    'AL': _('ALBANIA'),
+    'AM': _('ARMENIA'),
+    'AN': _('NETHERLANDS ANTILLES'),
+    'AO': _('ANGOLA'),
+    'AR': _('ARGENTINA'),
+    'AT': _('AUSTRIA'),
+    'AU': _('AUSTRALIA'),
+    'AW': _('ARUBA'),
+    'AZ': _('AZERBAIJAN'),
+    'BA': _('BOSNIA-HERZEGOVINA'),
+    'BB': _('BARBADOS'),
+    'BE': _('BELGIUM'),
+    'BF': _('BURKINA FASO'),
+    'BG': _('BULGARIA'),
+    'BH': _('BAHRAIN'),
+    'BI': _('BURUNDI'),
+    'BJ': _('BENIN'),
+    'BM': _('BERMUDA'),
+    'BN': _('BRUNEI DARUSSALAM'),
+    'BO': _('BOLIVIA'),
+    'BR': _('BRAZIL'),
+    'BS': _('BAHAMAS'),
+    'BT': _('BHUTAN'),
+    'BW': _('BOTSWANA'),
+    'BZ': _('BELIZE'),
+    'CA': _('CANADA'),
+    'CD': _('DEMOCRATIC REPUBLIC OF CONGO'),
+    'CG': _('CONGO'),
+    'CH': _('SWITZERLAND'),
+    'CK': _('COOK ISLANDS'),
+    'CL': _('CHILE'),
+    'CN': _('CHINA (domestic Chinese bank transactions only)'),
+    'C2': _('CHINA (For CUP, bank card and cross-border transactions)'),
+    'CO': _('COLOMBIA'),
+    'CR': _('COSTA RICA'),
+    'CV': _('CAPE VERDE'),
+    'CY': _('CYPRUS'),
+    'CZ': _('CZECH REPUBLIC'),
+    'DE': _('GERMANY'),
+    'DJ': _('DJIBOUTI'),
+    'DK': _('DENMARK'),
+    'DM': _('DOMINICA'),
+    'DO': _('DOMINICAN REPUBLIC'),
+    'DZ': _('ALGERIA'),
+    'EC': _('ECUADOR'),
+    'EE': _('ESTONIA'),
+    'EG': _('EGYPT'),
+    'ER': _('ERITERIA'),
+    'ES': _('SPAIN'),
+    'ET': _('ETHIOPIA'),
+    'FI': _('FINLAND'),
+    'FJ': _('FIJI'),
+    'FK': _('FALKLAND ISLANDS (MALVINAS)'),
+    'FM': _('MICRONESIA, FEDERATED STATES OF'),
+    'FR': _('FRANCE'),
+    'GA': _('GABON'),
+    'GB': _('UNITED KINGDOM'),
+    'GD': _('GRENADA'),
+    'GE': _('GEORGIA'),
+    'GF': _('FRENCH GUIANA'),
+    'GI': _('GIBRALTAR'),
+    'GL': _('GREENLAND'),
+    'GM': _('GAMBIA'),
+    'GN': _('GUINEA'),
+    'GP': _('GUADELOUPE'),
+    'GR': _('GREECE'),
+    'GT': _('GUATEMALA'),
+    'GU': _('GUAM'),
+    'GW': _('GUINEA BISSAU'),
+    'GY': _('GUYANA'),
+    'HK': _('HONG KONG'),
+    'HN': _('HONDURAS'),
+    'HR': _('CROATIA'),
+    'HU': _('HUNGARY'),
+    'ID': _('INDONESIA'),
+    'IE': _('IRELAND'),
+    'IL': _('ISRAEL'),
+    'IN': _('INDIA'),
+    'IS': _('ICELAND'),
+    'IT': _('ITALY'),
+    'JM': _('JAMAICA'),
+    'JO': _('JORDAN'),
+    'JP': _('JAPAN'),
+    'KE': _('KENYA'),
+    'KG': _('KYRGYZSTAN'),
+    'KH': _('CAMBODIA'),
+    'KI': _('KIRIBATI'),
+    'KM': _('COMOROS'),
+    'KN': _('SAINT KITTS AND NEVIS'),
+    'KR': _('SOUTH KOREA'),
+    'KW': _('KUWAIT'),
+    'KY': _('CAYMAN ISLANDS'),
+    'KZ': _('KAZAKHSTAN'),
+    'LA': _('LAOS'),
+    'LC': _('SAINT LUCIA'),
+    'LI': _('LIECHTENSTEIN'),
+    'LK': _('SRI LANKA'),
+    'LS': _('LESOTHO'),
+    'LT': _('LITHUANIA'),
+    'LU': _('LUXEMBOURG'),
+    'LV': _('LATVIA'),
+    'MA': _('MOROCCO'),
+    'MG': _('MADAGASCAR'),
+    'MH': _('MARSHALL ISLANDS'),
+    'ML': _('MALI'),
+    'MN': _('MONGOLIA'),
+    'MQ': _('MARTINIQUE'),
+    'MR': _('MAURITANIA'),
+    'MS': _('MONTSERRAT'),
+    'MT': _('MALTA'),
+    'MU': _('MAURITIUS'),
+    'MV': _('MALDIVES'),
+    'MW': _('MALAWI'),
+    'MX': _('MEXICO'),
+    'MY': _('MALAYSIA'),
+    'MZ': _('MOZAMBIQUE'),
+    'NA': _('NAMIBIA'),
+    'NC': _('NEW CALEDONIA'),
+    'NE': _('NIGER'),
+    'NF': _('NORFOLK ISLAND'),
+    'NI': _('NICARAGUA'),
+    'NL': _('NETHERLANDS'),
+    'NO': _('NORWAY'),
+    'NP': _('NEPAL'),
+    'NR': _('NAURU'),
+    'NU': _('NIUE'),
+    'NZ': _('NEW ZEALAND'),
+    'OM': _('OMAN'),
+    'PA': _('PANAMA'),
+    'PE': _('PERU'),
+    'PF': _('FRENCH POLYNESIA'),
+    'PG': _('PAPUA NEW GUINEA'),
+    'PH': _('PHILIPPINES'),
+    'PL': _('POLAND'),
+    'PM': _('SAINT PIERRE AND MIQUELON'),
+    'PN': _('PITCAIRN'),
+    'PT': _('PORTUGAL'),
+    'PW': _('PALAU'),
+    'QA': _('QATAR'),
+    'RE': _('REUNION'),
+    'RO': _('ROMANIA'),
+    'RS': _('SERBIA'),
+    'RU': _('RUSSIAN FEDERATION'),
+    'RW': _('RWANDA'),
+    'SA': _('SAUDI ARABIA'),
+    'SB': _('SOLOMON ISLANDS'),
+    'SC': _('SEYCHELLES'),
+    'SE': _('SWEDEN'),
+    'SG': _('SINGAPORE'),
+    'SH': _('SAINT HELENA'),
+    'SI': _('SLOVENIA'),
+    'SJ': _('SVALBARD AND JAN MAYEN'),
+    'SK': _('SLOVAKIA'),
+    'SL': _('SIERRA LEONE'),
+    'SM': _('SAN MARINO'),
+    'SN': _('SENEGAL'),
+    'SO': _('SOMALIA'),
+    'SR': _('SURINAME'),
+    'ST': _('SAO TOME AND PRINCIPE'),
+    'SV': _('EL SALVADOR'),
+    'SZ': _('SWAZILAND'),
+    'TC': _('TURKS AND CAICOS ISLANDS'),
+    'TD': _('CHAD'),
+    'TG': _('TOGO'),
+    'TH': _('THAILAND'),
+    'TJ': _('TAJIKISTAN'),
+    'TM': _('TURKMENISTAN'),
+    'TN': _('TUNISIA'),
+    'TO': _('TONGA'),
+    'TR': _('TURKEY'),
+    'TT': _('TRINIDAD AND TOBAGO'),
+    'TV': _('TUVALU'),
+    'TW': _('TAIWAN, PROVINCE OF CHINA'),
+    'TZ': _('TANZANIA, UNITED REPUBLIC OF'),
+    'UA': _('UKRAINE'),
+    'UG': _('UGANDA'),
+    'US': _('UNITED STATES'),
+    'UY': _('URUGUAY'),
+    'VA': _('HOLY SEE (VATICAN CITY STATE)'),
+    'VC': _('SAINT VINCENT AND THE GRENADINES'),
+    'VE': _('VENEZUELA'),
+    'VG': _('VIRGIN ISLANDS, BRITISH'),
+    'VN': _('VIETNAM'),
+    'VU': _('VANUATU'),
+    'WF': _('WALLIS AND FUTUNA'),
+    'WS': _('SAMOA'),
+    'YE': _('YEMEN'),
+    'YT': _('MAYOTTE'),
+    'ZA': _('SOUTH AFRICA'),
+    'ZM': _('ZAMBIA'),
+    }
+
+
+#: A vocabulary of paypal supported countries
+COUNTRIES_VOCAB = SimpleIkobaVocabulary(
+    *[(val, key) for key, val in COUNTRIES.items()])
Index: /main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/tests/test_paypal_countries.py
===================================================================
--- /main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/tests/test_paypal_countries.py	(revision 12179)
+++ /main/waeup.ikoba/branches/uli-payments/src/waeup/ikoba/payments/tests/test_paypal_countries.py	(revision 12179)
@@ -0,0 +1,38 @@
+import unittest
+from zope.i18nmessageid.message import Message as i18nMessage
+from zope.interface.verify import verifyObject
+from zope.schema.interfaces import IVocabularyTokenized, ITerm
+from waeup.ikoba.payments.paypal_countries import COUNTRIES, COUNTRIES_VOCAB
+
+
+class CountryTests(unittest.TestCase):
+
+    def test_countries_is_dict(self):
+        # COUNTRIES is available
+        assert isinstance(COUNTRIES, dict)
+
+    def test_countries_contains_i18n_messages(self):
+        # the COUNTRIES values are i18n messages
+        assert 'DE' in COUNTRIES.keys()
+        assert isinstance(COUNTRIES['DE'], i18nMessage)
+
+
+class CountriesVocabTests(unittest.TestCase):
+
+    def test_countries_vocab_tokenized(self):
+        # we can get a countries source suitable for forms etc.
+        verifyObject(IVocabularyTokenized, COUNTRIES_VOCAB)
+
+    def test_countries_vocab_i18nized(self):
+        # vocab titles are i18nized
+        result = COUNTRIES_VOCAB.getTerm('DE')
+        assert ITerm.providedBy(result)
+        self.assertEqual(result.title, u'GERMANY')
+        assert isinstance(result.title, i18nMessage)
+
+    def test_countries_vocab_tokens_are_string(self):
+        # vocab tokens are simple strings
+        result = COUNTRIES_VOCAB.getTerm('DE')
+        assert ITerm.providedBy(result)
+        assert result.token == 'DE'
+        assert result.value == 'DE'
