2009-10-20 10:52:23 +00:00
# -*- coding: utf-8 -*-
2007-11-26 15:46:03 +00:00
##############################################################################
2009-11-20 11:33:49 +00:00
#
2009-10-14 12:32:15 +00:00
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
2008-06-16 11:00:21 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is free software: you can redistribute it and/or modify
2009-10-14 12:32:15 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2007-11-26 15:46:03 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2009-10-14 12:32:15 +00:00
# GNU Affero General Public License for more details.
2007-11-26 15:46:03 +00:00
#
2009-10-14 12:32:15 +00:00
# You should have received a copy of the GNU Affero General Public License
2009-11-20 11:33:49 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2007-11-26 15:46:03 +00:00
#
##############################################################################
2011-01-12 16:06:08 +00:00
import locale
import logging
2007-11-26 15:46:03 +00:00
from osv import fields , osv
2008-12-10 13:35:06 +00:00
from locale import localeconv
2010-03-08 06:41:15 +00:00
import tools
2010-05-03 23:49:53 +00:00
from tools . safe_eval import safe_eval as eval
2010-10-11 13:01:41 +00:00
from tools . translate import _
2010-12-30 09:17:34 +00:00
2007-11-26 15:46:03 +00:00
class lang ( osv . osv ) :
2008-07-22 14:24:36 +00:00
_name = " res.lang "
2008-12-10 13:35:06 +00:00
_description = " Languages "
2009-05-11 19:45:28 +00:00
2011-01-12 16:06:08 +00:00
_disallowed_datetime_patterns = tools . DATETIME_FORMATS_MAP . keys ( )
_disallowed_datetime_patterns . remove ( ' % y ' ) # this one is in fact allowed, just not good practice
2010-12-30 09:17:34 +00:00
def install_lang ( self , cr , uid , * * args ) :
2011-01-07 12:32:07 +00:00
lang = tools . config . get ( ' lang ' )
if not lang :
return False
lang_ids = self . search ( cr , uid , [ ( ' code ' , ' = ' , lang ) ] )
2011-01-04 05:45:12 +00:00
values_obj = self . pool . get ( ' ir.values ' )
2011-01-03 12:19:49 +00:00
if not lang_ids :
2011-01-07 12:32:07 +00:00
lang_id = self . load_lang ( cr , uid , lang )
2011-01-04 05:45:12 +00:00
default_value = values_obj . get ( cr , uid , ' default ' , False , ' res.partner ' )
if not default_value :
2011-01-07 12:32:07 +00:00
values_obj . set ( cr , uid , ' default ' , False , ' lang ' , [ ' res.partner ' ] , lang )
2010-12-30 09:17:34 +00:00
return True
def load_lang ( self , cr , uid , lang , lang_name = None ) :
# create the language with locale information
fail = True
logger = logging . getLogger ( ' i18n ' )
iso_lang = tools . get_iso_codes ( lang )
for ln in tools . get_locales ( lang ) :
try :
locale . setlocale ( locale . LC_ALL , str ( ln ) )
fail = False
break
except locale . Error :
continue
if fail :
lc = locale . getdefaultlocale ( ) [ 0 ]
msg = ' Unable to get information for locale %s . Information from the default locale ( %s ) have been used. '
logger . warning ( msg , lang , lc )
if not lang_name :
lang_name = tools . get_languages ( ) . get ( lang , lang )
def fix_xa0 ( s ) :
2011-01-10 15:19:12 +00:00
""" Fix badly-encoded non-breaking space Unicode character from locale.localeconv(),
coercing to utf - 8 , as some platform seem to output localeconv ( ) in their system
encoding , e . g . Windows - 1252 """
2010-12-30 09:17:34 +00:00
if s == ' \xa0 ' :
return ' \xc2 \xa0 '
return s
2011-01-12 16:06:08 +00:00
def fix_datetime_format ( format ) :
""" Python ' s strftime supports only the format directives
that are available on the platform ' s libc, so in order to
be 100 % cross - platform we map to the directives required by
the C standard ( 1989 version ) , always available on platforms
with a C standard implementation . """
for pattern , replacement in tools . DATETIME_FORMATS_MAP . iteritems ( ) :
format = format . replace ( pattern , replacement )
2011-01-10 15:19:12 +00:00
return str ( format )
2010-12-30 09:17:34 +00:00
lang_info = {
' code ' : lang ,
' iso_code ' : iso_lang ,
' name ' : lang_name ,
' translatable ' : 1 ,
2011-01-12 16:06:08 +00:00
' date_format ' : fix_datetime_format ( locale . nl_langinfo ( locale . D_FMT ) ) ,
' time_format ' : fix_datetime_format ( locale . nl_langinfo ( locale . T_FMT ) ) ,
2010-12-30 09:17:34 +00:00
' decimal_point ' : fix_xa0 ( str ( locale . localeconv ( ) [ ' decimal_point ' ] ) ) ,
' thousands_sep ' : fix_xa0 ( str ( locale . localeconv ( ) [ ' thousands_sep ' ] ) ) ,
}
2011-01-03 12:19:49 +00:00
lang_id = False
2010-12-30 09:17:34 +00:00
try :
2011-01-03 12:19:49 +00:00
lang_id = self . create ( cr , uid , lang_info )
2010-12-30 09:17:34 +00:00
finally :
tools . resetlocale ( )
2011-01-03 12:19:49 +00:00
return lang_id
2010-12-30 09:17:34 +00:00
2011-01-12 16:06:08 +00:00
def _check_format ( self , cr , uid , ids , context = None ) :
for lang in self . browse ( cr , uid , ids , context = context ) :
for pattern in self . _disallowed_datetime_patterns :
if ( lang . time_format and pattern in lang . time_format ) \
or ( lang . date_format and pattern in lang . date_format ) :
return False
return True
2008-12-10 13:35:06 +00:00
def _get_default_date_format ( self , cursor , user , context = { } ) :
2009-04-06 15:59:16 +00:00
return ' % m/ %d / % Y '
2009-05-11 19:45:28 +00:00
2008-12-10 13:35:06 +00:00
def _get_default_time_format ( self , cursor , user , context = { } ) :
return ' % H: % M: % S '
2009-05-11 19:45:28 +00:00
2008-07-22 14:24:36 +00:00
_columns = {
' name ' : fields . char ( ' Name ' , size = 64 , required = True ) ,
2010-12-03 16:09:07 +00:00
' code ' : fields . char ( ' Locale Code ' , size = 16 , required = True , help = ' This field is used to set/get locales for user ' ) ,
' iso_code ' : fields . char ( ' ISO code ' , size = 16 , required = False , help = ' This ISO code is the name of po files to use for translations ' ) ,
2008-07-22 14:24:36 +00:00
' translatable ' : fields . boolean ( ' Translatable ' ) ,
' active ' : fields . boolean ( ' Active ' ) ,
2008-12-10 13:35:06 +00:00
' direction ' : fields . selection ( [ ( ' ltr ' , ' Left-to-Right ' ) , ( ' rtl ' , ' Right-to-Left ' ) ] , ' Direction ' , required = True ) ,
' date_format ' : fields . char ( ' Date Format ' , size = 64 , required = True ) ,
' time_format ' : fields . char ( ' Time Format ' , size = 64 , required = True ) ,
2009-11-20 11:33:49 +00:00
' grouping ' : fields . char ( ' Separator Format ' , size = 64 , required = True , help = " The Separator Format should be like [,n] where 0 < n :starting from Unit digit.-1 will end the separation. e.g. [3,2,-1] will represent 106500 to be 1,06,500;[1,2,-1] will represent it to be 106,50,0;[3] will represent it as 106,500. Provided ' , ' as the thousand separator in each case. " ) ,
2008-12-10 13:35:06 +00:00
' decimal_point ' : fields . char ( ' Decimal Separator ' , size = 64 , required = True ) ,
' thousands_sep ' : fields . char ( ' Thousands Separator ' , size = 64 ) ,
2008-07-22 14:24:36 +00:00
}
_defaults = {
' active ' : lambda * a : 1 ,
' translatable ' : lambda * a : 0 ,
' direction ' : lambda * a : ' ltr ' ,
2008-12-10 13:35:06 +00:00
' date_format ' : _get_default_date_format ,
' time_format ' : _get_default_time_format ,
' grouping ' : lambda * a : ' [] ' ,
' decimal_point ' : lambda * a : ' . ' ,
' thousands_sep ' : lambda * a : ' , ' ,
2008-07-22 14:24:36 +00:00
}
2009-01-29 23:20:17 +00:00
_sql_constraints = [
( ' name_uniq ' , ' unique (name) ' , ' The name of the language must be unique ! ' ) ,
( ' code_uniq ' , ' unique (code) ' , ' The code of the language must be unique ! ' ) ,
]
2010-05-14 13:04:25 +00:00
2011-01-12 16:06:08 +00:00
_constraints = [
( _check_format , ' Invalid date/time format directive specified. Please refer to the list of allowed directives, displayed when you edit a language. ' , [ ' time_format ' , ' date_format ' ] )
]
2010-03-08 06:41:15 +00:00
@tools.cache ( skiparg = 3 )
2010-03-31 10:28:36 +00:00
def _lang_data_get ( self , cr , uid , lang_id , monetary = False ) :
2008-12-10 13:35:06 +00:00
conv = localeconv ( )
2010-05-14 13:04:25 +00:00
lang_obj = self . browse ( cr , uid , lang_id )
2008-12-10 13:35:06 +00:00
thousands_sep = lang_obj . thousands_sep or conv [ monetary and ' mon_thousands_sep ' or ' thousands_sep ' ]
2010-03-08 06:41:15 +00:00
decimal_point = lang_obj . decimal_point
grouping = lang_obj . grouping
2010-12-30 09:17:34 +00:00
return ( grouping , thousands_sep , decimal_point )
2010-03-08 06:41:15 +00:00
def write ( self , cr , uid , ids , vals , context = None ) :
for lang_id in ids :
self . _lang_data_get . clear_cache ( cr . dbname , lang_id = lang_id )
return super ( lang , self ) . write ( cr , uid , ids , vals , context )
2010-10-11 13:01:41 +00:00
def unlink ( self , cr , uid , ids , context = None ) :
if context is None :
context = { }
languages = self . read ( cr , uid , ids , [ ' code ' , ' active ' ] , context = context )
for language in languages :
2010-12-09 15:04:42 +00:00
ctx_lang = context . get ( ' lang ' )
2010-10-11 13:01:41 +00:00
if language [ ' code ' ] == ' en_US ' :
raise osv . except_osv ( _ ( ' User Error ' ) , _ ( " Base Language ' en_US ' can not be deleted ! " ) )
2010-12-09 15:04:42 +00:00
if ctx_lang and ( language [ ' code ' ] == ctx_lang ) :
2010-10-11 13:01:41 +00:00
raise osv . except_osv ( _ ( ' User Error ' ) , _ ( " You cannot delete the language which is User ' s Preferred Language ! " ) )
if language [ ' active ' ] :
raise osv . except_osv ( _ ( ' User Error ' ) , _ ( " You cannot delete the language which is Active ! \n Please de-activate the language first. " ) )
trans_obj = self . pool . get ( ' ir.translation ' )
trans_ids = trans_obj . search ( cr , uid , [ ( ' lang ' , ' = ' , language [ ' code ' ] ) ] , context = context )
trans_obj . unlink ( cr , uid , trans_ids , context = context )
return super ( lang , self ) . unlink ( cr , uid , ids , context = context )
2010-03-08 06:41:15 +00:00
def _group ( self , cr , uid , ids , s , monetary = False , grouping = False , thousands_sep = ' ' ) :
grouping = eval ( grouping )
2010-12-30 09:17:34 +00:00
2008-12-10 13:35:06 +00:00
if not grouping :
return ( s , 0 )
2010-05-14 13:04:25 +00:00
2008-12-10 13:35:06 +00:00
result = " "
seps = 0
spaces = " "
2010-12-30 09:17:34 +00:00
2008-12-10 13:35:06 +00:00
if s [ - 1 ] == ' ' :
sp = s . find ( ' ' )
spaces = s [ sp : ]
s = s [ : sp ]
2010-12-30 09:17:34 +00:00
2008-12-10 13:35:06 +00:00
while s and grouping :
# if grouping is -1, we are done
if grouping [ 0 ] == - 1 :
break
# 0: re-use last group ad infinitum
elif grouping [ 0 ] != 0 :
#process last group
group = grouping [ 0 ]
grouping = grouping [ 1 : ]
if result :
result = s [ - group : ] + thousands_sep + result
seps + = 1
else :
result = s [ - group : ]
s = s [ : - group ]
if s and s [ - 1 ] not in " 0123456789 " :
# the leading string is only spaces and signs
return s + result + spaces , seps
if not result :
return s + spaces , seps
if s :
result = s + thousands_sep + result
seps + = 1
return result + spaces , seps
2010-03-08 06:41:15 +00:00
def format ( self , cr , uid , ids , percent , value , grouping = False , monetary = False ) :
2008-12-10 13:35:06 +00:00
""" Format() will return the language-specific output for float values """
if percent [ 0 ] != ' % ' :
raise ValueError ( " format() must be given exactly one %c har format specifier " )
2010-12-30 09:17:34 +00:00
lang_grouping , thousands_sep , decimal_point = self . _lang_data_get ( cr , uid , ids [ 0 ] , monetary )
2009-11-20 11:33:49 +00:00
2008-12-10 13:35:06 +00:00
formatted = percent % value
# floats and decimal ints need special action!
if percent [ - 1 ] in ' eEfFgG ' :
seps = 0
parts = formatted . split ( ' . ' )
2009-11-20 11:33:49 +00:00
2008-12-10 13:35:06 +00:00
if grouping :
2010-05-14 13:04:25 +00:00
parts [ 0 ] , seps = self . _group ( cr , uid , ids , parts [ 0 ] , monetary = monetary , grouping = lang_grouping , thousands_sep = thousands_sep )
2008-12-10 13:35:06 +00:00
formatted = decimal_point . join ( parts )
while seps :
sp = formatted . find ( ' ' )
if sp == - 1 : break
formatted = formatted [ : sp ] + formatted [ sp + 1 : ]
seps - = 1
elif percent [ - 1 ] in ' diu ' :
if grouping :
2010-03-08 06:41:15 +00:00
formatted = self . _group ( cr , uid , ids , formatted , monetary = monetary , grouping = lang_grouping , thousands_sep = thousands_sep ) [ 0 ]
2008-12-10 13:35:06 +00:00
return formatted
# import re, operator
# _percent_re = re.compile(r'%(?:\((?P<key>.*?)\))?'
# r'(?P<modifiers>[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]')
2007-11-26 15:46:03 +00:00
lang ( )
2008-07-23 15:01:27 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: