summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-10-08 23:20:25 -0400
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2010-10-08 23:20:25 -0400
commit9c53495e198aabcb2fe3363d0f5c92470a7f780e (patch)
treeb8a692d22df4c2f74b09771cff2d81dbd40bd3e7
parente80e9bde56efebc17e4ede78b10f5207d030872f (diff)
parent360a6965eb904e447981c8f6c497097428318e15 (diff)
downloadaskbot-9c53495e198aabcb2fe3363d0f5c92470a7f780e.tar.gz
askbot-9c53495e198aabcb2fe3363d0f5c92470a7f780e.tar.bz2
askbot-9c53495e198aabcb2fe3363d0f5c92470a7f780e.zip
merged with master branch
-rw-r--r--askbot/__init__.py2
-rw-r--r--askbot/conf/external_keys.py67
-rw-r--r--askbot/conf/settings_wrapper.py21
-rw-r--r--askbot/conf/skin_counter_settings.py10
-rw-r--r--askbot/context.py2
-rw-r--r--askbot/deps/django_authopenid/backends.py14
-rw-r--r--askbot/deps/django_authopenid/forms.py5
-rw-r--r--askbot/deps/django_authopenid/util.py29
-rw-r--r--askbot/deps/django_authopenid/views.py99
-rw-r--r--askbot/models/base.py4
-rw-r--r--askbot/models/content.py1
-rw-r--r--askbot/models/meta.py1
-rw-r--r--askbot/setup_templates/settings.py4
-rwxr-xr-xaskbot/skins/default/media/jquery-openid/jquery.openid.js19
-rwxr-xr-x[-rw-r--r--]askbot/skins/default/media/js/com.cnprog.i18n.js71
15 files changed, 280 insertions, 69 deletions
diff --git a/askbot/__init__.py b/askbot/__init__.py
index 8a5c99be..8e5e3242 100644
--- a/askbot/__init__.py
+++ b/askbot/__init__.py
@@ -22,7 +22,7 @@ def get_version():
"""returns version of the askbot app
this version is meaningful for pypi only
"""
- return '0.6.12'
+ return '0.6.14'
#todo: maybe send_mail functions belong to models
#or the future API
diff --git a/askbot/conf/external_keys.py b/askbot/conf/external_keys.py
index acf637f8..81f17818 100644
--- a/askbot/conf/external_keys.py
+++ b/askbot/conf/external_keys.py
@@ -2,17 +2,17 @@
External service key settings
"""
from askbot.conf.settings_wrapper import settings
-from askbot.deps.livesettings import ConfigurationGroup, StringValue
+from askbot.deps import livesettings
from django.utils.translation import ugettext as _
from django.conf import settings as django_settings
-EXTERNAL_KEYS = ConfigurationGroup(
+EXTERNAL_KEYS = livesettings.ConfigurationGroup(
'EXTERNAL_KEYS',
_('Keys to connect the site with external services like Facebook, etc.')
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'GOOGLE_SITEMAP_CODE',
description=_('Google site verification key'),
@@ -28,7 +28,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'GOOGLE_ANALYTICS_KEY',
description=_('Google Analytics key'),
@@ -43,7 +43,16 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.BooleanValue(
+ EXTERNAL_KEYS,
+ 'USE_RECAPTCHA',
+ description=_('Enable recaptcha (keys below are required)'),
+ default=False
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'RECAPTCHA_KEY',
description=_('Recaptcha public key')
@@ -51,7 +60,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'RECAPTCHA_SECRET',
description=_('Recaptcha private key'),
@@ -64,9 +73,8 @@ settings.register(
)
)
-
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'FACEBOOK_KEY',
description=_('Facebook public API key'),
@@ -81,7 +89,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'FACEBOOK_SECRET',
description=_('Facebook secret key')
@@ -89,7 +97,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'TWITTER_KEY',
description=_('Twitter consumer key'),
@@ -102,7 +110,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'TWITTER_SECRET',
description=_('Twitter consumer secret'),
@@ -110,7 +118,7 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'LINKEDIN_KEY',
description=_('LinkedIn consumer key'),
@@ -123,9 +131,42 @@ settings.register(
)
settings.register(
- StringValue(
+ livesettings.StringValue(
EXTERNAL_KEYS,
'LINKEDIN_SECRET',
description=_('LinkedIn consumer secret'),
)
)
+
+settings.register(
+ livesettings.BooleanValue(
+ EXTERNAL_KEYS,
+ 'USE_LDAP_FOR_PASSWORD_LOGIN',
+ description=_('User LDAP authentication for the password login'),
+ defaut=False
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ EXTERNAL_KEYS,
+ 'LDAP_PROVIDER_NAME',
+ description=_('LDAP service provider name')
+ )
+)
+
+settings.register(
+ livesettings.StringValue(
+ EXTERNAL_KEYS,
+ 'LDAP_URL',
+ description=_('URL for the LDAP service')
+ )
+)
+
+settings.register(
+ livesettings.LongStringValue(
+ EXTERNAL_KEYS,
+ 'HOW_TO_CHANGE_LDAP_PASSWORD',
+ description=_('Explain how to change LDAP password')
+ )
+)
diff --git a/askbot/conf/settings_wrapper.py b/askbot/conf/settings_wrapper.py
index a567d007..aac8f071 100644
--- a/askbot/conf/settings_wrapper.py
+++ b/askbot/conf/settings_wrapper.py
@@ -20,8 +20,10 @@ at run time
askbot.deps.livesettings is a module developed for satchmo project
"""
+from django.core.cache import cache
from askbot.deps.livesettings import SortedDotDict, config_register
from askbot.deps.livesettings.functions import config_get
+from askbot.deps.livesettings import signals
class ConfigSettings(object):
"""A very simple Singleton wrapper for settings
@@ -74,11 +76,24 @@ class ConfigSettings(object):
self.__group_map[key] = group_key
def as_dict(self):
+ settings = cache.get('askbot-livesettings')
+ if settings:
+ return settings
+ else:
+ self.prime_cache()
+ return cache.get('askbot-livesettings')
+
+ @classmethod
+ def prime_cache(cls, **kwargs):
+ """reload all settings into cache as dictionary
+ """
out = dict()
- for key in self.__instance.keys():
+ for key in cls.__instance.keys():
#todo: this is odd that I could not use self.__instance.items() mapping here
- out[key] = self.__instance[key].value
- return out
+ out[key] = cls.__instance[key].value
+ cache.set('askbot-livesettings', out)
+
+signals.configuration_value_changed.connect(ConfigSettings.prime_cache)
#settings instance to be used elsewhere in the project
settings = ConfigSettings()
diff --git a/askbot/conf/skin_counter_settings.py b/askbot/conf/skin_counter_settings.py
index 6c6d6a64..54713cb9 100644
--- a/askbot/conf/skin_counter_settings.py
+++ b/askbot/conf/skin_counter_settings.py
@@ -79,8 +79,8 @@ settings.register(
SKIN_COUNTER_SETTINGS,
'COLORS_VOTE_COUNTER_MAX_FG',
default=Color.NewFromHtml(
- settings.COLORS_VOTE_COUNTER_MAX_BG
- ).DarkerColor(0.7).html,
+ '#a9d0f5'
+ ).DarkerColor(0.7).html,
description=_('Foreground color for votes = MAX'),
help_text=_('HTML color name or hex value'),
hidden=True,
@@ -155,8 +155,10 @@ settings.register(
SKIN_COUNTER_SETTINGS,
'COLORS_VIEW_COUNTER_MAX_FG',
default=Color.NewFromHtml(
- settings.COLORS_VIEW_COUNTER_MAX_BG
- ).DarkerColor(0.7).html,
+ '#ff8000'
+ ).DarkerColor(
+ 0.7
+ ).html,
description=_('Foreground color for views = MAX'),
help_text=_('HTML color name or hex value'),
hidden=True,
diff --git a/askbot/context.py b/askbot/context.py
index 447f46dc..73f6018a 100644
--- a/askbot/context.py
+++ b/askbot/context.py
@@ -1,5 +1,7 @@
from django.conf import settings
from askbot.conf import settings as askbot_settings
+import datetime
+
def application_settings(context):
my_settings = askbot_settings.as_dict()
my_settings['LANGUAGE_CODE'] = settings.LANGUAGE_CODE
diff --git a/askbot/deps/django_authopenid/backends.py b/askbot/deps/django_authopenid/backends.py
index 554afda5..75e40252 100644
--- a/askbot/deps/django_authopenid/backends.py
+++ b/askbot/deps/django_authopenid/backends.py
@@ -29,6 +29,7 @@ class AuthBackend(object):
email_key = None,
oauth_user_id = None,#used with oauth
facebook_user_id = None,#user with facebook
+ ldap_user_id = None,#for ldap
method = None,#requried parameter
):
"""this authentication function supports many login methods
@@ -105,9 +106,20 @@ class AuthBackend(object):
elif method == 'facebook':
try:
+ assert(provider_name == 'facebook')
assoc = UserAssociation.objects.get(
openid_url = facebook_user_id,
- provider_name = 'facebook'
+ provider_name = provider_name
+ )
+ user = assoc.user
+ except UserAssociation.DoesNotExist:
+ return None
+
+ elif method == 'ldap':
+ try:
+ assoc = UserAssociation.objects.get(
+ openid_url = ldap_user_id,
+ provider_name = provider_name
)
user = assoc.user
except UserAssociation.DoesNotExist:
diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py
index 2d4b57d6..c7022b5d 100644
--- a/askbot/deps/django_authopenid/forms.py
+++ b/askbot/deps/django_authopenid/forms.py
@@ -323,6 +323,11 @@ class ClassicRegisterForm(SetPasswordForm):
email = UserEmailField()
login_provider = PasswordLoginProviderField()
#fields password1 and password2 are inherited
+
+class SafeClassicRegisterForm(ClassicRegisterForm):
+ """this form uses recaptcha in addition
+ to the base register form
+ """
recaptcha = ReCaptchaField()
class ChangePasswordForm(SetPasswordForm):
diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py
index 594c70d1..716cc5dd 100644
--- a/askbot/deps/django_authopenid/util.py
+++ b/askbot/deps/django_authopenid/util.py
@@ -156,6 +156,20 @@ def get_provider_name(openid_url):
url_bits = base_url.split('.')
return url_bits[-2].lower()
+def use_password_login():
+ """password login is activated
+ either if USE_RECAPTCHA is false
+ of if recaptcha keys are set correctly
+ """
+ if askbot_settings.USE_RECAPTCHA:
+ if askbot_settings.RECAPTCHA_KEY and askbot_settings.RECAPTCHA_SECRET:
+ return True
+ else:
+ logging.critical('if USE_RECAPTCHA == True, set recaptcha keys!!!')
+ return False
+ else:
+ return True
+
def get_major_login_providers():
"""returns a tuple with data about login providers
whose icons are to be shown in large format
@@ -176,7 +190,8 @@ def get_major_login_providers():
describes name of required extra token - e.g. "XYZ user name"
"""
data = SortedDict()
- if askbot_settings.RECAPTCHA_KEY and askbot_settings.RECAPTCHA_SECRET:
+
+ if use_password_login():
data['local'] = {
'name': 'local',
'display_name': askbot_settings.APP_SHORT_NAME,
@@ -186,6 +201,7 @@ def get_major_login_providers():
'change_password_prompt': _('Change your password'),
'icon_media_path': askbot_settings.LOCAL_LOGIN_ICON,
}
+
if askbot_settings.FACEBOOK_KEY and askbot_settings.FACEBOOK_SECRET:
data['facebook'] = {
'name': 'facebook',
@@ -573,3 +589,14 @@ def get_facebook_user_id(request):
return fb_response['uid']
except Exception, e:
raise FacebookError(e)
+
+def ldap_check_password(username, password):
+ import ldap
+ try:
+ ldap_session = ldap.initialize(askbot_settings.LDAP_URL)
+ ldap_session.simple_bind_s(username, password)
+ ldap_session.unbind_s()
+ return True
+ except ldap.LDAPError, e:
+ logging.critical(unicode(e))
+ return False
diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py
index b3b07721..e003bf8c 100644
--- a/askbot/deps/django_authopenid/views.py
+++ b/askbot/deps/django_authopenid/views.py
@@ -298,37 +298,66 @@ def signin(
if login_form.cleaned_data['login_type'] == 'password':
password_action = login_form.cleaned_data['password_action']
- if password_action == 'login':
- user = authenticate(
+ if askbot_settings.USE_LDAP_FOR_PASSWORD_LOGIN:
+ assert(password_action == 'login')
+ ldap_provider_name = askbot_settings.LDAP_PROVIDER_NAME
+ username = login_form.cleaned_data['username']
+ if util.ldap_check_password(
+ username,
+ login_form.cleaned_data['password']
+ ):
+ user = authenticate(
+ ldap_user_id = username,
+ provider_name = ldap_provider_name,
+ method = 'ldap'
+ )
+ if user is not None:
+ login(request, user)
+ return HttpResponseRedirect(next_url)
+ else:
+ request.session['login_provider_name'] = ldap_provider_name
+ request.session['user_identifier'] = username
+ request.method = 'GET'
+ return finalize_generic_signin(
+ request = request,
+ user = user,
+ user_identifier = username,
+ login_provider_name = ldap_provider_name,
+ redirect_url = next_url
+ )
+ else:
+ if password_action == 'login':
+ user = authenticate(
username = login_form.cleaned_data['username'],
password = login_form.cleaned_data['password'],
provider_name = provider_name,
method = 'password'
)
- if user is None:
- login_form.set_password_login_error()
- else:
- login(request, user)
- #todo: here we might need to set cookies
- #for external login sites
- return HttpResponseRedirect(next_url)
- elif password_action == 'change_password':
- if request.user.is_authenticated():
- new_password = login_form.cleaned_data['new_password']
- AuthBackend.set_password(
- user=request.user,
- password=new_password,
- provider_name=provider_name
- )
- request.user.message_set.create(
+ if user is None:
+ login_form.set_password_login_error()
+ else:
+ login(request, user)
+ #todo: here we might need to set cookies
+ #for external login sites
+ return HttpResponseRedirect(next_url)
+ elif password_action == 'change_password':
+ if request.user.is_authenticated():
+ new_password = \
+ login_form.cleaned_data['new_password']
+ AuthBackend.set_password(
+ user=request.user,
+ password=new_password,
+ provider_name=provider_name
+ )
+ request.user.message_set.create(
message = _('Your new password saved')
)
- return HttpResponseRedirect(next_url)
- else:
- logging.critical(
- 'unknown password action %s' % password_action
- )
- raise Http404
+ return HttpResponseRedirect(next_url)
+ else:
+ logging.critical(
+ 'unknown password action %s' % password_action
+ )
+ raise Http404
elif login_form.cleaned_data['login_type'] == 'openid':
#initiate communication process
@@ -393,7 +422,7 @@ def signin(
request = request,
user = user,
user_identifier = user_id,
- login_provider_name = 'facebook',
+ login_provider_name = provider_name,
redirect_url = next_url
)
@@ -507,6 +536,7 @@ def show_signin_view(
'account_recovery_form': account_recovery_form,
'openid_error_message': request.REQUEST.get('msg',''),
'account_recovery_message': account_recovery_message,
+ 'use_password_login': util.use_password_login(),
}
major_login_providers = util.get_major_login_providers()
@@ -808,9 +838,14 @@ def signup_with_password(request):
#this is safe because second decorator cleans this field
provider_name = request.REQUEST['login_provider']
+ if askbot_settings.USE_RECAPTCHA:
+ RegisterForm = forms.SafeClassicRegisterForm
+ else:
+ RegisterForm = forms.ClassicRegisterForm
+
logging.debug('request method was %s' % request.method)
if request.method == 'POST':
- form = forms.ClassicRegisterForm(request.POST)
+ form = RegisterForm(request.POST)
email_feeds_form = askbot_forms.SimpleEmailSubscribeForm(request.POST)
#validation outside if to remember form values
@@ -871,12 +906,12 @@ def signup_with_password(request):
logging.debug('create classic account forms were invalid')
else:
#todo: here we have duplication of get_password_login_provider...
- form = forms.ClassicRegisterForm(
- initial={
- 'next':next,
- 'login_provider': provider_name
- }
- )
+ form = RegisterForm(
+ initial={
+ 'next':next,
+ 'login_provider': provider_name
+ }
+ )
email_feeds_form = askbot_forms.SimpleEmailSubscribeForm()
logging.debug('printing legacy signup form')
context_data = {
diff --git a/askbot/models/base.py b/askbot/models/base.py
index 2ef874d6..f81d6172 100644
--- a/askbot/models/base.py
+++ b/askbot/models/base.py
@@ -1,4 +1,5 @@
import datetime
+import cgi
from django.db import models
from django.utils.html import strip_tags
from django.contrib.auth.models import User
@@ -29,6 +30,9 @@ def parse_post_text(post):
text = post.get_text()
+ if post._escape_html:
+ text = cgi.escape(text)
+
if post._urlize:
text = html.urlize(text)
diff --git a/askbot/models/content.py b/askbot/models/content.py
index 636b093e..6c524125 100644
--- a/askbot/models/content.py
+++ b/askbot/models/content.py
@@ -39,6 +39,7 @@ class Content(models.Model):
flagged_items = generic.GenericRelation(FlaggedItem)
_use_markdown = True
+ _escape_html = False #markdow does the escaping
_urlize = False
class Meta:
diff --git a/askbot/models/meta.py b/askbot/models/meta.py
index 9aa372cc..bcdfa2c6 100644
--- a/askbot/models/meta.py
+++ b/askbot/models/meta.py
@@ -108,6 +108,7 @@ class Comment(base.MetaContent, base.UserContent):
_urlize = True
_use_markdown = False
+ _escape_html = True
class Meta(base.MetaContent.Meta):
ordering = ('-added_at',)
diff --git a/askbot/setup_templates/settings.py b/askbot/setup_templates/settings.py
index f313f641..c9075c2b 100644
--- a/askbot/setup_templates/settings.py
+++ b/askbot/setup_templates/settings.py
@@ -44,10 +44,6 @@ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# system time zone.
TIME_ZONE = 'America/Chicago'
-# Language code for this installation. All choices can be found here:
-# http://www.i18nguy.com/unicode/language-identifiers.html
-LANGUAGE_CODE = 'en-us'
-
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
diff --git a/askbot/skins/default/media/jquery-openid/jquery.openid.js b/askbot/skins/default/media/jquery-openid/jquery.openid.js
index 3efc8172..7c89958c 100755
--- a/askbot/skins/default/media/jquery-openid/jquery.openid.js
+++ b/askbot/skins/default/media/jquery-openid/jquery.openid.js
@@ -1,4 +1,3 @@
-//jQuery OpenID Plugin 1.1 Copyright 2009 Jarrett Vance http://jvance.com/pages/jQueryOpenIdPlugin.xhtml
$.fn.authenticator = function() {
var signin_page = $(this);
var signin_form = $('#signin-form');
@@ -302,15 +301,17 @@ $.fn.authenticator = function() {
var password_button = $('input[name=login_with_password]');
var submit_action = submit_login_with_password;
var create_pw_link = $('a.create-password-account')
- create_pw_link.html($.i18n._('Create a password-protected account'));
- var url = create_pw_link.attr('href');
- if (url.indexOf('?') !== -1){
- url = url.replace(/\?.*$/,'?login_provider=' + provider_name);
- }
- else{
- url += '?login_provider=' + provider_name;
+ if (create_pw_link.length > 0){
+ create_pw_link.html($.i18n._('Create a password-protected account'));
+ var url = create_pw_link.attr('href');
+ if (url.indexOf('?') !== -1){
+ url = url.replace(/\?.*$/,'?login_provider=' + provider_name);
+ }
+ else{
+ url += '?login_provider=' + provider_name;
+ }
+ create_pw_link.attr('href', url);
}
- create_pw_link.attr('href', url);
password_action_input.val('login');
}
password_input_fields.show();
diff --git a/askbot/skins/default/media/js/com.cnprog.i18n.js b/askbot/skins/default/media/js/com.cnprog.i18n.js
index 24bdab90..4cf2495c 100644..100755
--- a/askbot/skins/default/media/js/com.cnprog.i18n.js
+++ b/askbot/skins/default/media/js/com.cnprog.i18n.js
@@ -1,4 +1,4 @@
-//var i18nLang;
+//var i18nLang;
var i18nZh = {
'insufficient privilege':'用户权限不在操作范围',
'cannot pick own answer as best':'不能设置自己的回答为最佳答案',
@@ -505,6 +505,74 @@ var i18nFr = {
'signin/': 'connexion/'
};
+var i18nIt = {
+ "anonymous users cannot vote":"Gli utenti anonimi non possono votare ",
+ 'add a comment': 'Aggiungi un commento',
+ 'add comment': 'OK',
+ 'anonymous users cannot delete/undelete': 'Gli utenti anonimi non possono cancellare/annullare la cancellazione',
+ 'anonymous users cannot flag offensive posts': 'Gli utenti anonimi non possono flaggare come offensivo questo post',
+ 'anonymous users cannot select favorite questions': 'Gli utenti anonimi non possono aggiungere domande ai preferiti',
+ 'bold': 'grassetto',
+ 'bulleted list': 'Lista',
+ 'can write': 'può scrivere ',
+ 'cannot flag message as offensive twice': 'non è possibile flaggare come offensivo più di una volta ',
+ 'cannot pick own answer as best': 'non è possibile assegnare come miglior risposta ad una propria domanda una propria risposta',
+ 'characters': 'caratteri rimanenti',
+ 'click to close': 'clicca per chiudere',
+ 'comments': 'commenti',
+ 'community karma points': ' punti reputazione - ',
+ 'confirm delete': 'conferma la cancellazione',
+ 'confirm delete comment': 'Vuoi davvero cancellare il commento?',
+ 'content cannot be empty': 'il contenuto non può essere vuoto',
+ 'content minchars': 'per favore inserisci più di {0} caratteri',
+ 'daily vote cap exhausted': 'Spiacente, hai raggiunto il limite odierno massimo di voti',
+ 'delete': 'elimina',
+ 'delete this comment': 'Elimina questo commento',
+ 'enter image url': 'inserisci l\'URL dell\'immagine, es. http://www.example.com/immagine.jpg \"titolo immagine\"',
+ 'enter url': 'inserisci l\'indirizzo web, e.g. <br />http://www.askbot.org/ </p>',
+ 'flag offensive cap exhausted': 'spiacente, hai raggiunto il limite odierno massimo di flag offensivi ',
+ 'heading': 'Titolo',
+ 'hide comments': 'Nascondi i commenti',
+ 'horizontal bar': 'barra orizzontale',
+ 'image': 'Immagine',
+ 'insufficient privilege': 'privilegi non sufficienti',
+ 'italic': 'corsivo',
+ 'link': 'Link',
+ 'loading...': 'Caricamento...',
+ 'need >15 points to report spam': 'Servono almeno 15 punti reputazione per segnalare come spam',
+ 'numbered list': 'Lista numerata',
+ 'please confirm offensive': 'sei certo che questo post sia offensivo, contenga spam, pubblicità, osservazioni poco idonee, ecc.?',
+ 'please enter title': 'Per favore inserisci il titolo',
+ 'please login': 'Per favore effettua il login',
+ 'please see': 'Per favore guarda',
+ 'post deleted': 'Post eliminato',
+ 'post recovered': 'Post recuperato',
+ 'preformatted text': 'Testo preformattato',
+ 'quote': 'cita',
+ 'redo': 'Esegui nuovamente',
+ 'tablimits info': 'fino a 5 tags, non più di 20 caratteri ognuno',
+ 'tags cannot be empty': 'Il campo Tags non può essere vuoto',
+ 'title minchars': 'per favore inserisci almeno {0} caratteri',
+ 'to comment, need': '(per commentare post di altre persone, la reputazione ',
+ 'undelete': 'elimina',
+ 'undo': 'annulla',
+ 'upload image': 'carica immagine',
+ 'questions/': 'domande/',
+ 'question/': 'domanda/',
+ 'delete/': 'elimina/',
+ 'comments/': 'commenti/',
+ 'answers/': 'risposte/',
+ 'vote/': 'voti/',
+ 'unmark-tag/':'unmark-tag/',
+ 'ignored/':'ignorato/',
+ 'mark-tag/':'mark-tag/',
+ 'interesting/':'interessante/',
+ 'command/':'command/',
+ 'moderate-user/': 'modera-utente/',
+ 'account/': 'account/',
+ 'signin/': 'accedi/'
+};
+
var i18n = {
'en':i18nEn,
'zh-cn':i18nZh,
@@ -513,6 +581,7 @@ var i18n = {
'de':i18nDe,
'ru':i18nRu,
'fr':i18nFr,
+ 'it':i18nIt,
'zh-tw':i18nZhtw
};