text: # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  # MIT License. See license.txt
  
  from __future__ import unicode_literals, print_function
  
  from six import iteritems
  
  """
  	frappe.translate
  	~~~~~~~~~~~~~~~~
  
  	Translation tools for frappe
  """
  
  import frappe, os, re, codecs, json
  from frappe.model.utils import render_include, InvalidIncludePath
  from frappe.utils import strip
  from jinja2 import TemplateError
  import itertools, operator
  
  def guess_language(lang_list=None):
  	"""Set `frappe.local.lang` from HTTP headers at beginning of request"""
  	lang_codes = frappe.request.accept_languages.values()
  	if not lang_codes:
  		return frappe.local.lang
  
  	guess = None
  	if not lang_list:
  		lang_list = get_all_languages() or []
  
  	for l in lang_codes:
  		code = l.strip()
  		if not isinstance(code, unicode):
  			code = unicode(code, 'utf-8')
  		if code in lang_list or code == "en":
  			guess = code
  			break
  
  		# check if parent language (pt) is setup, if variant (pt-BR)
  		if "-" in code:
  			code = code.split("-")[0]
  			if code in lang_list:
  				guess = code
  				break
  
  	return guess or frappe.local.lang
  
  def get_user_lang(user=None):
  	"""Set frappe.local.lang from user preferences on session beginning or resumption"""
  	if not user:
  		user = frappe.session.user
  
  	# via cache
  	lang = frappe.cache().hget("lang", user)
  
  	if not lang:
  
  		# if defined in user profile
  		lang = frappe.db.get_value("User", user, "language")
  		if not lang:
  			lang = frappe.db.get_default("lang")
  
  		if not lang:
  			lang = frappe.local.lang or 'en'
  
  		frappe.cache().hset("lang", user, lang)
  
  	return lang
  
  def get_lang_code(lang):
  	return frappe.db.get_value('Language', {'language_name': lang}) or lang
  
  def set_default_language(lang):
  	"""Set Global default language"""
  	frappe.db.set_default("lang", lang)
  	frappe.local.lang = lang
  
  def get_all_languages():
  	"""Returns all language codes ar, ch etc"""
  	def _get():
  		if not frappe.db:
  			frappe.connect()
  		return frappe.db.sql_list('select name from tabLanguage')
  	return frappe.cache().get_value('languages', _get)
  
  def get_lang_dict():
  	"""Returns all languages in dict format, full name is the key e.g. `{"english":"en"}`"""
  	return dict(frappe.db.sql('select language_name, name from tabLanguage'))
  
  def get_dict(fortype, name=None):
  	"""Returns translation dict for a type of object.
  
  	 :param fortype: must be one of `doctype`, `page`, `report`, `include`, `jsfile`, `boot`
  	 :param name: name of the document for which assets are to be returned.
  	 """
  	fortype = fortype.lower()
  	cache = frappe.cache()
  	asset_key = fortype + ":" + (name or "-")
  	translation_assets = cache.hget("translation_assets", frappe.local.lang, shared=True) or {}
  
  	if not asset_key in translation_assets:
  		if fortype=="doctype":
  			messages = get_messages_from_doctype(name)
  		elif fortype=="page":
  			messages = get_messages_from_page(name)
  		elif fortype=="report":
  			messages = get_messages_from_report(name)
  		elif fortype=="include":
  			messages = get_messages_from_include_files()
  		elif fortype=="jsfile":
  			messages = get_messages_from_file(name)
  		elif fortype=="boot":
  			messages = get_messages_from_include_files()
  			messages += frappe.db.sql("select 'Print Format:', name from `tabPrint Format`")
  			messages += frappe.db.sql("select 'DocType:', name from tabDocType")
  			messages += frappe.db.sql("select 'Role:', name from tabRole")
  			messages += frappe.db.sql("select 'Module:', name from `tabModule Def`")
  			messages += frappe.db.sql("select 'Module:', label from `tabDesktop Icon` where standard=1 or owner=%s",
  				frappe.session.user)
  
  		message_dict = make_dict_from_messages(messages)
  		message_dict.update(get_dict_from_hooks(fortype, name))
  
  		# remove untranslated
  		message_dict = {k:v for k, v in iteritems(message_dict) if k!=v}
  
  		translation_assets[asset_key] = message_dict
  
  		cache.hset("translation_assets", frappe.local.lang, translation_assets, shared=True)
  
  	return translation_assets[asset_key]
  
  def get_dict_from_hooks(fortype, name):
  	translated_dict = {}
  
  	hooks = frappe.get_hooks("get_translated_dict")
  	for (hook_fortype, fortype_name) in hooks:
  		if hook_fortype == fortype and fortype_name == name:
  			for method in hooks[(hook_fortype, fortype_name)]:
  				translated_dict.update(frappe.get_attr(method)())
  
  	return translated_dict
  
  def add_lang_dict(code):
  	"""Extracts messages and returns Javascript code snippet to be appened at the end
  	of the given script
  
  	:param code: Javascript code snippet to which translations needs to be appended."""
  	messages = extract_messages_from_code(code)
  	messages = [message for pos, message in messages]
  	code += "\n\n$.extend(frappe._messages, %s)" % json.dumps(make_dict_from_messages(messages))
  	return code
  
  def make_dict_from_messages(messages, full_dict=None):
  	"""Returns translated messages as a dict in Language specified in `frappe.local.lang`
  
  	:param messages: List of untranslated messages
  	"""
  	out = {}
  	if full_dict==None:
  		full_dict = get_full_dict(frappe.local.lang)
  
  	for m in messages:
  		if m[1] in full_dict:
  			out[m[1]] = full_dict[m[1]]
  	return out
  
  def get_lang_js(fortype, name):
  	"""Returns code snippet to be appended at the end of a JS script.
  
  	:param fortype: Type of object, e.g. `DocType`
  	:param name: Document name
  	"""
  	return "\n\n$.extend(frappe._messages, %s)" % json.dumps(get_dict(fortype, name))
  
  def get_full_dict(lang):
  	"""Load and return the entire translations dictionary for a language from :meth:`frape.cache`
  
  	:param lang: Language Code, e.g. `hi`
  	"""
  	if not lang:
  		return {}
  
  	# found in local, return!
  	if getattr(frappe.local, 'lang_full_dict', None) and frappe.local.lang_full_dict.get(lang, None):
  		return frappe.local.lang_full_dict
  
  	frappe.local.lang_full_dict = load_lang(lang)
  
  	try:
  		# get user specific transaltion data
  		user_translations = get_user_translations(lang)
  	except Exception:
  		user_translations = None
  
  	if user_translations:
  		frappe.local.lang_full_dict.update(user_translations)
  
  	return frappe.local.lang_full_dict
  
  def load_lang(lang, apps=None):
  	"""Combine all translations from `.csv` files in all `apps`.
  	For derivative languages (es-GT), take translations from the
  	base language (es) and then update translations from the child (es-GT)"""
  
  	if lang=='en':
  		return {}
  
  	out = frappe.cache().hget("lang_full_dict", lang, shared=True)
  	if not out:
  		out = {}
  		for app in (apps or frappe.get_all_apps(True)):
  			path = os.path.join(frappe.get_pymodule_path(app), "translations", lang + ".csv")
  			out.update(get_translation_dict_from_file(path, lang, app) or {})
  
  		if '-' in lang:
  			parent = lang.split('-')[0]
  			parent_out = load_lang(parent)
  			parent_out.update(out)
  			out = parent_out
  
  		frappe.cache().hset("lang_full_dict", lang, out, shared=True)
  
  	return out or {}
  
  def get_translation_dict_from_file(path, lang, app):
  	"""load translation dict from given path"""
  	cleaned = {}
  	if os.path.exists(path):
  		csv_content = read_csv_file(path)
  
  		for item in csv_content:
  			if len(item)==3:
  				# with file and line numbers
  				cleaned[item[1]] = strip(item[2])
  
  			elif len(item)==2:
  				cleaned[item[0]] = strip(item[1])
  
  			elif item:
  				raise Exception("Bad translation in '{app}' for language '{lang}': {values}".format(
  					app=app, lang=lang, values=repr(item).encode("utf-8")
  				))
  
  	return cleaned
  
  def get_user_translations(lang):
  	out = frappe.cache().hget('lang_user_translations', lang)
  	if out is None:
  		out = {}
  		for fields in frappe.get_all('Translation',
  			fields= ["source_name", "target_name"], filters={'language': lang}):
  				out.update({fields.source_name: fields.target_name})
  		frappe.cache().hset('lang_user_translations', lang, out)
  
  	return out
  
  
  def clear_cache():
  	"""Clear all translation assets from :meth:`frappe.cache`"""
  	cache = frappe.cache()
  	cache.delete_key("langinfo")
  
  	# clear translations saved in boot cache
  	cache.delete_key("bootinfo")
  	cache.delete_key("lang_full_dict", shared=True)
  	cache.delete_key("translation_assets", shared=True)
  	cache.delete_key("lang_user_translations")
  
  def get_messages_for_app(app):
  	"""Returns all messages (list) for a specified `app`"""
  	messages = []
  	modules = ", ".join(['"{}"'.format(m.title().replace("_", " ")) \
  		for m in frappe.local.app_modules[app]])
  
  	# doctypes
  	if modules:
  		for name in frappe.db.sql_list("""select name from tabDocType
  			where module in ({})""".format(modules)):
  			messages.extend(get_messages_from_doctype(name))
  
  		# pages
  		for name, title in frappe.db.sql("""select name, title from tabPage
  			where module in ({})""".format(modules)):
  			messages.append((None, title or name))
  			messages.extend(get_messages_from_page(name))
  
  
  		# reports
  		for name in frappe.db.sql_list("""select tabReport.name from tabDocType, tabReport
  			where tabReport.ref_doctype = tabDocType.name
  				and tabDocType.module in ({})""".format(modules)):
  			messages.append((None, name))
  			messages.extend(get_messages_from_report(name))
  			for i in messages:
  				if not isinstance(i, tuple):
  					raise Exception
  
  	# workflow based on app.hooks.fixtures
  	messages.extend(get_messages_from_workflow(app_name=app))
  
  	# custom fields based on app.hooks.fixtures
  	messages.extend(get_messages_from_custom_fields(app_name=app))
  
  	# app_include_files
  	messages.extend(get_all_messages_from_js_files(app))
  
  	# server_messages
  	messages.extend(get_server_messages(app))
  	return deduplicate_messages(messages)
  
  def get_messages_from_doctype(name):
  	"""Extract all translatable messages for a doctype. Includes labels, Python code,
  	Javascript code, html templates"""
  	messages = []
  	meta = frappe.get_meta(name)
  
  	messages = [meta.name, meta.module]
  
  	if meta.description:
  		messages.append(meta.description)
  
  	# translations of field labels, description and options
  	for d in meta.get("fields"):
  		messages.extend([d.label, d.description])
  
  		if d.fieldtype=='Select' and d.options:
  			options = d.options.split('\n')
  			if not "icon" in options[0]:
  				messages.extend(options)
  
  	# translations of roles
  	for d in meta.get("permissions"):
  		if d.role:
  			messages.append(d.role)
  
  	messages = [message for message in messages if message]
  	messages = [('DocType: ' + name, message) for message in messages if is_translatable(message)]
  
  	# extract from js, py files
  	doctype_file_path = frappe.get_module_path(meta.module, "doctype", meta.name, meta.name)
  	messages.extend(get_messages_from_file(doctype_file_path + ".js"))
  	messages.extend(get_messages_from_file(doctype_file_path + "_list.js"))
  	messages.extend(get_messages_from_file(doctype_file_path + "_list.html"))
  	messages.extend(get_messages_from_file(doctype_file_path + "_calendar.js"))
  
  	# workflow based on doctype
  	messages.extend(get_messages_from_workflow(doctype=name))
  
  	return messages
  
  def get_messages_from_workflow(doctype=None, app_name=None):
  	assert doctype or app_name, 'doctype or app_name should be provided'
  
  	# translations for Workflows
  	workflows = []
  	if doctype:
  		workflows = frappe.get_all('Workflow', filters={'document_type': doctype})
  	else:
  		fixtures = frappe.get_hooks('fixtures', app_name=app_name) or []
  		for fixture in fixtures:
  			if isinstance(fixture, basestring) and fixture == 'Worflow':
  				workflows = frappe.get_all('Workflow')
  				break
  			elif isinstance(fixture, dict) and fixture.get('dt', fixture.get('doctype')) == 'Workflow':
  				workflows.extend(frappe.get_all('Workflow', filters=fixture.get('filters')))
  
  	messages  = []
  	for w in workflows:
  		states = frappe.db.sql(
  			'select distinct state from `tabWorkflow Document State` where parent=%s',
  			(w['name'],), as_dict=True)
  
  		messages.extend([('Workflow: ' + w['name'], state['state']) for state in states if is_translatable(state['state'])])
  
  		states = frappe.db.sql(
  			'select distinct message from `tabWorkflow Document State` where parent=%s and message is not null',
  			(w['name'],), as_dict=True)
  
  		messages.extend([("Workflow: " + w['name'], state['message'])
  			for state in states if is_translatable(state['message'])])
  
  		actions = frappe.db.sql(
  			'select distinct action from `tabWorkflow Transition` where parent=%s',
  			(w['name'],), as_dict=True)
  
  		messages.extend([("Workflow: " + w['name'], action['action']) \
  			for action in actions if is_translatable(action['action'])])
  
  	return messages
  
  def get_messages_from_custom_fields(app_name):
  	fixtures = frappe.get_hooks('fixtures', app_name=app_name) or []
  	custom_fields = []
  
  	for fixture in fixtures:
  		if isinstance(fixture, basestring) and fixture == 'Custom Field':
  			custom_fields = frappe.get_all('Custom Field', fields=['name','label', 'description', 'fieldtype', 'options'])
  			break
  		elif isinstance(fixture, dict) and fixture.get('dt', fixture.get('doctype')) == 'Custom Field':
  			custom_fields.extend(frappe.get_all('Custom Field', filters=fixture.get('filters'),
  				fields=['name','label', 'description', 'fieldtype', 'options']))
  
  	messages = []
  	for cf in custom_fields:
  		for prop in ('label', 'description'):
  			if not cf.get(prop) or not is_translatable(cf[prop]):
  				continue
  			messages.append(('Custom Field - {}: {}'.format(prop, cf['name']), cf[prop]))
  		if cf['fieldtype'] == 'Selection' and cf.get('options'):
  			for option in cf['options'].split('\n'):
  				if option and 'icon' not in option and is_translatable(option):
  					messages.append(('Custom Field - Description: ' + cf['name'], option))
  
  	return messages
  
  def get_messages_from_page(name):
  	"""Returns all translatable strings from a :class:`frappe.core.doctype.Page`"""
  	return _get_messages_from_page_or_report("Page", name)
  
  def get_messages_from_report(name):
  	"""Returns all translatable strings from a :class:`frappe.core.doctype.Report`"""
  	report = frappe.get_doc("Report", name)
  	messages = _get_messages_from_page_or_report("Report", name,
  		frappe.db.get_value("DocType", report.ref_doctype, "module"))
  	# TODO position here!
  	if report.query:
  		messages.extend([(None, message) for message in re.findall('"([^:,^"]*):', report.query) if is_translatable(message)])
  	messages.append((None,report.report_name))
  	return messages
  
  def _get_messages_from_page_or_report(doctype, name, module=None):
  	if not module:
  		module = frappe.db.get_value(doctype, name, "module")
  
  	doc_path = frappe.get_module_path(module, doctype, name)
  
  	messages = get_messages_from_file(os.path.join(doc_path, frappe.scrub(name) +".py"))
  
  	if os.path.exists(doc_path):
  		for filename in os.listdir(doc_path):
  			if filename.endswith(".js") or filename.endswith(".html"):
  				messages += get_messages_from_file(os.path.join(doc_path, filename))
  
  	return messages
  
  def get_server_messages(app):
  	"""Extracts all translatable strings (tagged with :func:`frappe._`) from Python modules
  		inside an app"""
  	messages = []
  	for basepath, folders, files in os.walk(frappe.get_pymodule_path(app)):
  		for dontwalk in (".git", "public", "locale"):
  			if dontwalk in folders: folders.remove(dontwalk)
  
  		for f in files:
  			if f.endswith(".py") or f.endswith(".html") or f.endswith(".js"):
  				messages.extend(get_messages_from_file(os.path.join(basepath, f)))
  
  	return messages
  
  def get_messages_from_include_files(app_name=None):
  	"""Returns messages from js files included at time of boot like desk.min.js for desk and web"""
  	messages = []
  	for file in (frappe.get_hooks("app_include_js", app_name=app_name) or []) + (frappe.get_hooks("web_include_js", app_name=app_name) or []):
  		messages.extend(get_messages_from_file(os.path.join(frappe.local.sites_path, file)))
  
  	return messages
  
  def get_all_messages_from_js_files(app_name=None):
  	"""Extracts all translatable strings from app `.js` files"""
  	messages = []
  	for app in ([app_name] if app_name else frappe.get_installed_apps()):
  		if os.path.exists(frappe.get_app_path(app, "public")):
  			for basepath, folders, files in os.walk(frappe.get_app_path(app, "public")):
  				if "frappe/public/js/lib" in basepath:
  					continue
  
  				for fname in files:
  					if fname.endswith(".js") or fname.endswith(".html"):
  						messages.extend(get_messages_from_file(os.path.join(basepath, fname)))
  
  	return messages
  
  def get_messages_from_file(path):
  	"""Returns a list of transatable strings from a code file
  
  	:param path: path of the code file
  	"""
  	apps_path = get_bench_dir()
  	if os.path.exists(path):
  		with open(path, 'r') as sourcefile:
  			return [(os.path.relpath(" +".join([path, str(pos)]), apps_path),
  					message) for pos, message in  extract_messages_from_code(sourcefile.read(), path.endswith(".py"))]
  	else:
  		# print "Translate: {0} missing".format(os.path.abspath(path))
  		return []
  
  def extract_messages_from_code(code, is_py=False):
  	"""Extracts translatable srings from a code file
  
  	:param code: code from which translatable files are to be extracted
  	:param is_py: include messages in triple quotes e.g. `_('''message''')`"""
  	try:
  		code = render_include(code)
  	except (TemplateError, ImportError, InvalidIncludePath):
  		# Exception will occur when it encounters John Resig's microtemplating code
  		pass
  
  	messages = []
  	messages += [(m.start(), m.groups()[0]) for m in re.compile('_\("([^"]*)"').finditer(code)]
  	messages += [(m.start(), m.groups()[0]) for m in re.compile("_\('([^']*)'").finditer(code)]
  	if is_py:
  		messages += [(m.start(), m.groups()[0]) for m in re.compile('_\("{3}([^"]*)"{3}.*\)').finditer(code)]
  
  	messages = [(pos, message) for pos, message in messages if is_translatable(message)]
  	return pos_to_line_no(messages, code)
  
  def is_translatable(m):
  	if re.search("[a-zA-Z]", m) and not m.startswith("fa fa-") and not m.endswith("px") and not m.startswith("eval:"):
  		return True
  	return False
  
  def pos_to_line_no(messages, code):
  	ret = []
  	messages = sorted(messages, key=lambda x: x[0])
  	newlines = [m.start() for m in re.compile('\\n').finditer(code)]
  	line = 1
  	newline_i = 0
  	for pos, message in messages:
  		while newline_i < len(newlines) and pos > newlines[newline_i]:
  			line+=1
  			newline_i+= 1
  		ret.append((line, message))
  	return ret
  
  def read_csv_file(path):
  	"""Read CSV file and return as list of list
  
  	:param path: File path"""
  	from csv import reader
  	with codecs.open(path, 'r', 'utf-8') as msgfile:
  		data = msgfile.read()
  
  		# for japanese! #wtf
  		data = data.replace(chr(28), "").replace(chr(29), "")
  		data = reader([r.encode('utf-8') for r in data.splitlines()])
  		newdata = [[unicode(val, 'utf-8') for val in row] for row in data]
  	return newdata
  
  def write_csv_file(path, app_messages, lang_dict):
  	"""Write translation CSV file.
  
  	:param path: File path, usually `[app]/translations`.
  	:param app_messages: Translatable strings for this app.
  	:param lang_dict: Full translated dict.
  	"""
  	app_messages.sort(lambda x,y: cmp(x[1], y[1]))
  	from csv import writer
  	with open(path, 'wb') as msgfile:
  		w = writer(msgfile, lineterminator='\n')
  		for p, m in app_messages:
  			t = lang_dict.get(m, '')
  			# strip whitespaces
  			t = re.sub('{\s?([0-9]+)\s?}', "{\g<1>}", t)
  			w.writerow([p.encode('utf-8') if p else '', m.encode('utf-8'), t.encode('utf-8')])
  
  def get_untranslated(lang, untranslated_file, get_all=False):
  	"""Returns all untranslated strings for a language and writes in a file
  
  	:param lang: Language code.
  	:param untranslated_file: Output file path.
  	:param get_all: Return all strings, translated or not."""
  	clear_cache()
  	apps = frappe.get_all_apps(True)
  
  	messages = []
  	untranslated = []
  	for app in apps:
  		messages.extend(get_messages_for_app(app))
  
  	messages = deduplicate_messages(messages)
  
  	def escape_newlines(s):
  		return (s.replace("\\\n", "|||||")
  				.replace("\\n", "||||")
  				.replace("\n", "|||"))
  
  	if get_all:
  		print(str(len(messages)) + " messages")
  		with open(untranslated_file, "w") as f:
  			for m in messages:
  				# replace \n with ||| so that internal linebreaks don't get split
  				f.write((escape_newlines(m[1]) + os.linesep).encode("utf-8"))
  	else:
  		full_dict = get_full_dict(lang)
  
  		for m in messages:
  			if not full_dict.get(m[1]):
  				untranslated.append(m[1])
  
  		if untranslated:
  			print(str(len(untranslated)) + " missing translations of " + str(len(messages)))
  			with open(untranslated_file, "w") as f:
  				for m in untranslated:
  					# replace \n with ||| so that internal linebreaks don't get split
  					f.write((escape_newlines(m) + os.linesep).encode("utf-8"))
  		else:
  			print("all translated!")
  
  def update_translations(lang, untranslated_file, translated_file):
  	"""Update translations from a source and target file for a given language.
  
  	:param lang: Language code (e.g. `en`).
  	:param untranslated_file: File path with the messages in English.
  	:param translated_file: File path with messages in language to be updated."""
  	clear_cache()
  	full_dict = get_full_dict(lang)
  
  	def restore_newlines(s):
  		return (s.replace("|||||", "\\\n")
  				.replace("| | | | |", "\\\n")
  				.replace("||||", "\\n")
  				.replace("| | | |", "\\n")
  				.replace("|||", "\n")
  				.replace("| | |", "\n"))
  
  	translation_dict = {}
  	for key, value in zip(frappe.get_file_items(untranslated_file, ignore_empty_lines=False),
  		frappe.get_file_items(translated_file, ignore_empty_lines=False)):
  
  		# undo hack in get_untranslated
  		translation_dict[restore_newlines(key)] = restore_newlines(value)
  
  	full_dict.update(translation_dict)
  
  	for app in frappe.get_all_apps(True):
  		write_translations_file(app, lang, full_dict)
  
  def import_translations(lang, path):
  	"""Import translations from file in standard format"""
  	clear_cache()
  	full_dict = get_full_dict(lang)
  	full_dict.update(get_translation_dict_from_file(path, lang, 'import'))
  
  	for app in frappe.get_all_apps(True):
  		write_translations_file(app, lang, full_dict)
  
  
  def rebuild_all_translation_files():
  	"""Rebuild all translation files: `[app]/translations/[lang].csv`."""
  	for lang in get_all_languages():
  		for app in frappe.get_all_apps():
  			write_translations_file(app, lang)
  
  def write_translations_file(app, lang, full_dict=None, app_messages=None):
  	"""Write a translation file for a given language.
  
  	:param app: `app` for which translations are to be written.
  	:param lang: Language code.
  	:param full_dict: Full translated language dict (optional).
  	:param app_messages: Source strings (optional).
  	"""
  	if not app_messages:
  		app_messages = get_messages_for_app(app)
  
  	if not app_messages:
  		return
  
  	tpath = frappe.get_pymodule_path(app, "translations")
  	frappe.create_folder(tpath)
  	write_csv_file(os.path.join(tpath, lang + ".csv"),
  		app_messages, full_dict or get_full_dict(lang))
  
  def send_translations(translation_dict):
  	"""Append translated dict in `frappe.local.response`"""
  	if "__messages" not in frappe.local.response:
  		frappe.local.response["__messages"] = {}
  
  	frappe.local.response["__messages"].update(translation_dict)
  
  def deduplicate_messages(messages):
  	ret = []
  	op = operator.itemgetter(1)
  	messages = sorted(messages, key=op)
  	for k, g in itertools.groupby(messages, op):
  		ret.append(g.next())
  	return ret
  
  def get_bench_dir():
  	return os.path.join(frappe.__file__, '..', '..', '..', '..')
  
  def rename_language(old_name, new_name):
  	if not frappe.db.exists('Language', new_name):
  		return
  
  	language_in_system_settings = frappe.db.get_single_value("System Settings", "language")
  	if language_in_system_settings == old_name:
  		frappe.db.set_value("System Settings", "System Settings", "language", new_name)
  
  	frappe.db.sql("""update `tabUser` set language=%(new_name)s where language=%(old_name)s""",
  		{ "old_name": old_name, "new_name": new_name })
  