#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
#
# Copyright 2018 黎慧剑
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
国际化文本处理模块
@module i18n
@file i18n.py
"""
import os
import sys
import copy
import json
import re
# 根据当前文件路径将包路径纳入, 在非安装的情况下可以引用到
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
from HiveNetCore.utils.file_tool import FileTool
from HiveNetCore.utils.global_var_tool import GlobalVarTool
__MOUDLE__ = 'i18n' # 模块名
__DESCRIPT__ = u'国际化文本处理模块' # 模块描述
__VERSION__ = '0.1.0' # 版本
__AUTHOR__ = u'黎慧剑' # 作者
__PUBLISH__ = '2018.08.29' # 发布日期
[文档]def set_global_i18n(i18n_obj):
"""
设置通用的SimpleI18N实例对象
@param {object} i18n_obj - SimpleI18N实例对象
"""
GlobalVarTool.set_global_var('SIMPLE_I18N_GLOBAL_OBJECT', i18n_obj)
[文档]def get_global_i18n():
"""
获取全局SimpleI18N实例对象
@returns {SimpleI18N} - 如果未设置返回None
"""
return GlobalVarTool.get_global_var('SIMPLE_I18N_GLOBAL_OBJECT')
def _(s, *args):
"""
封装对字符串的国际化简化处理函数
@param {string} s - 要进行国际化处理的字符串
@param {tuple} args - 进行占位符替换的变量
@returns {string} - 国际化转换后的字符串
@example
1、直接进行字符串转换
print(_('success!'))
2、通过占位符替换的情况
print(_('my name is $1, i am $2 years old', 'snaker', '30'))
"""
i18n_obj = GlobalVarTool.get_global_var('SIMPLE_I18N_GLOBAL_OBJECT')
if i18n_obj is None:
return s
else:
return i18n_obj.translate(s, args)
[文档]def init_global_i18n():
"""
初始化HiveNetCore的国际化控件, 包括:
1、生成SimpleI18N类, 并设置到全局变量
2、装载HiveNetCore的基础国际化配置信息
"""
_i18n_obj = get_global_i18n()
if _i18n_obj is None:
_i18n_obj = SimpleI18N()
set_global_i18n(_i18n_obj)
# 装载所需的配置信息, 错误码
_base_path = os.path.abspath(os.path.dirname(__file__) + '/')
_error_code_path = os.path.realpath(_base_path + '/hivenet_error_code/')
_i18n_obj.load_trans_from_dir(
trans_file_path=_error_code_path,
trans_file_prefix='errorcode',
encoding='utf-8',
append=True
)
[文档]class SimpleI18N(object):
"""
国际化文本处理类
"""
#############################
# 变量
#############################
lang = 'en' # 默认语言
__trans_dict = None # 语言信息字典
@property
def trans_dict(self):
"""
返回已装载的多国语言字典
格式如下:
{
'en': {
'success' : 'success',
'failed' : 'failed',
'my name is $1' : 'my name is $1'
},
'zh': {
'success' : '成功',
'failed' : '失败',
'my name is $1' : '我的名字是$1'
}
}
@property {dict}
"""
return self.__trans_dict
[文档] def __init__(self, lang='en', trans_file_path=None, trans_file_prefix='',
encoding='utf-8', auto_loads=False):
"""
构造函数
@param {string} lang='en' - 指定默认语言, 例如en、zh等
@param {string} trans_file_path=None - 语言信息文件所在路径, 如果为None则代表不处理信息文件
@param {string} trans_file_prefix='' - 语言信息文件前缀,
例如前缀为test, 信息文件名为test_en.json、test_zh.json等
@param {string} encoding='utf-8' - 解析文件的编码
@param {bool} auto_loads=False - 是否自动加载语言信息文件
"""
self.__trans_dict = dict()
self.lang = lang
if auto_loads and trans_file_path is not None:
# 加载语言信息文件
self.load_trans_from_dir(
trans_file_path=trans_file_path,
trans_file_prefix=trans_file_prefix,
encoding=encoding,
append=False
)
[文档] def load_trans_from_dir(self, trans_file_path, trans_file_prefix, encoding='utf-8', append=True):
"""
从指定路径加载语言信息文件到对象中
@param {string} trans_file_path - 语言信息文件所在路径, 如果为None则代表不处理信息文件
@param {string} trans_file_prefix - 语言信息文件前缀,
例如前缀为test, 信息文件名为test_en.json、test_zh.json等
@param {string} encoding='utf-8' - 解析文件的编码
@param {bool} append=True - 是否追加模式, 如果是则以增量方式更新, 否则覆盖原来的配置
"""
file_list = FileTool.get_filelist(
path=trans_file_path,
regex_str=r'^' + trans_file_prefix + r'_\S+\.json$',
is_fullname=True
)
for file in file_list:
# 循环加载语言信息文件
file_name = os.path.split(os.path.realpath(file))[1]
file_lang = re.sub(r'\.json$', '', re.sub(
r'^' + trans_file_prefix + r'_', '', file_name))
self.load_trans_from_file(file_full_path=file, lang=file_lang,
encoding=encoding, append=append)
[文档] def load_trans_from_file(self, file_full_path, lang, encoding='utf-8', append=True):
"""
从语言信息文件加载到对象中
@param {string} file_full_path - 语言信息文件全路径( 含文件名)
@param {string} lang - 对应的语言, 例如en、zh等
@param {string} encoding='utf-8' - 解析文件的编码
@param {bool} append=True - 是否追加模式, 如果是则以增量方式更新, 否则覆盖原来的配置
"""
json_obj = {}
with open(file_full_path, 'rt', encoding=encoding) as f:
json_obj = json.load(f)
self.load_trans_from_json(json_obj, lang=lang, append=append)
[文档] def load_trans_from_str(self, json_str, lang, append=True):
"""
从JSON字符串中加载语言信息到对象中
@param {string} json_str - JSON字符串
@param {string} lang - 对应的语言, 例如en、zh等
@param {bool} append=True - 是否追加模式, 如果是则以增量方式更新, 否则覆盖原来的配置
"""
json_obj = json.loads(json_str)
self.load_trans_from_json(json_obj, lang=lang, append=append)
[文档] def load_trans_from_json(self, json_obj, lang, append=True):
"""
从JSON实例变量中加载语言信息到对象中
@param {object} json_obj - 信息字典的json对象
@param {string} lang - 对应的语言, 例如en、zh等
@param {bool} append=True - 是否追加模式, 如果是则以增量方式更新, 否则覆盖原来的配置
"""
if append and lang in self.__trans_dict.keys():
# 追加模式, 逐条更新
for key in json_obj.keys():
self.__trans_dict[lang][key] = json_obj[key]
else:
# 覆盖模式, 直接重新设置值即可
self.__trans_dict[lang] = copy.deepcopy(json_obj)
[文档] def translate(self, msg_id, replace_para=(), lang=None):
"""
返回指定语言的文本
@param {string} msg_id - 要翻译的语言ID标识
@param {tuple} replace_para=() - 进行占位符替换的变量
@param {string} lang=None - 要翻译的语言, 如果不指定则采用初始化对象的默认语言
@returns {string} - 国际化转换后的字符串
"""
temp_lang = lang
if lang is None:
temp_lang = self.lang
s = msg_id
if temp_lang in self.__trans_dict.keys() and msg_id in self.__trans_dict[temp_lang].keys():
# 可以找到对应的语言信息
s = self.__trans_dict[temp_lang][msg_id]
# 替换占位符
i = 1 # 记录是第几个
for para in replace_para:
if s.find('$' + str(i)) >= 0:
s = re.sub(r'\$' + str(i), str(para).replace('\\', '\\\\'), s) # 如果字符串有'\'会抛异常
i = i + 1
# 处理完成
return s
if __name__ == '__main__':
# 当程序自己独立运行时执行的操作
# 打印版本信息
print(('模块名: %s - %s\n'
'作者: %s\n'
'发布日期: %s\n'
'版本: %s' % (__MOUDLE__, __DESCRIPT__, __AUTHOR__, __PUBLISH__, __VERSION__)))