refactor i18n processing and sign-in validation.

This commit is contained in:
kunw 2016-05-21 17:20:39 +08:00
parent 02c182d178
commit 2bf1742ecb
17 changed files with 328 additions and 543 deletions

View File

@ -2,8 +2,8 @@ appname = registry
runmode = dev
[lang]
types = en-US|zh-CN|de-DE|ru-RU
names = en-US|zh-CN|de-DE|ru-RU
types = en-US|zh-CN
names = English|中文
[dev]
httpport = 80

View File

@ -8,7 +8,6 @@ import (
"github.com/astaxie/beego"
"github.com/beego/i18n"
"github.com/vmware/harbor/dao"
"github.com/vmware/harbor/utils/log"
)
@ -74,6 +73,7 @@ func (b *BaseController) Prepare() {
b.Data["Lang"] = curLang.Lang
b.Data["CurLang"] = curLang.Name
b.Data["RestLangs"] = restLangs
b.Data["SupportLanguages"] = supportLanguages
authMode := strings.ToLower(os.Getenv("AUTH_MODE"))
if authMode == "" {
@ -82,28 +82,6 @@ func (b *BaseController) Prepare() {
b.AuthMode = authMode
b.Data["AuthMode"] = b.AuthMode
selfRegistration := strings.ToLower(os.Getenv("SELF_REGISTRATION"))
if selfRegistration == "on" {
b.SelfRegistration = true
}
sessionUserID := b.GetSession("userId")
if sessionUserID != nil {
b.Data["Username"] = b.GetSession("username")
b.Data["UserId"] = sessionUserID.(int)
var err error
b.IsAdmin, err = dao.IsAdminRole(sessionUserID.(int))
if err != nil {
log.Errorf("Error occurred in IsAdminRole:%v", err)
b.CustomAbort(http.StatusInternalServerError, "Internal error.")
}
}
b.Data["IsAdmin"] = b.IsAdmin
b.Data["SelfRegistration"] = b.SelfRegistration
}
func (bc *BaseController) Forward(title, templateName string) {
@ -120,6 +98,27 @@ func (bc *BaseController) Forward(title, templateName string) {
var langTypes []*langType
type CommonController struct {
BaseController
}
func (cc *CommonController) Render() error {
return nil
}
func (cc *CommonController) LogOut() {
cc.DestroySession()
}
func (cc *CommonController) SwitchLanguage() {
lang := cc.GetString("lang")
if _, exist := supportLanguages[lang]; exist {
cc.SetSession("lang", lang)
cc.Data["Lang"] = lang
}
cc.Redirect(cc.Ctx.Request.Header.Get("Referer"), http.StatusFound)
}
func init() {
//conf/app.conf -> os.Getenv("config_path")

View File

@ -14,18 +14,6 @@ import (
"github.com/vmware/harbor/utils/log"
)
type CommonController struct {
BaseController
}
func (cc *CommonController) Render() error {
return nil
}
func (cc *CommonController) LogOut() {
cc.DestroySession()
}
type messageDetail struct {
Hint string
URL string

View File

@ -12,7 +12,3 @@
text-align: left;
}
.single {
margin-right: 0;
}

View File

@ -13,17 +13,17 @@
vm.currentLanguage = I18nService().getCurrentLanguage();
vm.languageName = I18nService().getLanguageName(vm.currentLanguage);
console.log('current language:' + I18nService().getCurrentLanguage());
vm.user = currentUser.get();
vm.setLanguage = setLanguage;
vm.logOut = logOut;
function setLanguage(name) {
I18nService().setCurrentLanguage(name);
$window.location.reload();
function setLanguage(language) {
I18nService().setCurrentLanguage(language);
$window.location.href = '/ng/language?lang=' + language;
}
function logOut() {
LogOutService()
.success(logOutSuccess)
@ -31,6 +31,7 @@
}
function logOutSuccess(data, status) {
currentUser.unset();
I18nService().unset();
$window.location.href= '/ng';
}
function logOutFailed(data, status) {

View File

@ -3,7 +3,7 @@
<div class="col-sm-offset-1 col-sm-10">
<input id="username" type="text" class="form-control" placeholder="// 'username_email' | tr //" name="uPrincipal" ng-change="vm.reset()" ng-model="user.principal" required>
<div class="error-message">
<div ng-messages="form.uPrincipal.$error" ng-if="form.uPrincipal.$touched">
<div ng-messages="form.uPrincipal.$error" ng-if="form.uPrincipal.$touched || form.$submitted">
<span ng-message="required">// 'username_is_required' | tr //</span>
</div>
</div>
@ -13,7 +13,7 @@
<div class="col-sm-offset-1 col-sm-10">
<input type="password" class="form-control" placeholder="// 'password' | tr //" name="uPassword" ng-change="vm.reset()" ng-model="user.password" required>
<div class="error-message">
<div ng-messages="form.uPassword.$error" ng-if="form.uPassword.$touched">
<div ng-messages="form.uPassword.$error" ng-if="form.uPassword.$touched || form.$submitted">
<span ng-message="required">// 'password_is_required' | tr //</span>
</div>
<span ng-show="vm.hasError">// vm.errorMessage | tr //</span>

View File

@ -1,468 +0,0 @@
var global_messages = {
'sign_in': {
'en-US': 'Sign In',
'zh-CN': '登录'
},
'sign_up': {
'en-US': 'Sign Up',
'zh-CN': '注册'
},
'forgot_password': {
'en-US': 'Forgot Password',
'zh-CN': '忘记密码'
},
'login_now': {
'en-US': 'Login Now',
'zh-CN': '立刻登录'
},
'its_easy_to_get_started': {
'en-US': 'It\'s easy to get started ...',
'zh-CN': '这很容易上手...'
},
'anybody_can_read_public_projects': {
'en-US': 'Anybody can read public projects',
'zh-CN': '任何人都可以访问公开的项目'
},
'create_projects_and_connect_repositories': {
'en-US': 'Create projects and connect repositories',
'zh-CN': '创建项目并关联镜像仓库'
},
'user_management_and_role_assignment': {
'en-US': 'User management and role assignment',
'zh-CN': '用户管理和角色分派'
},
'why_use_harbor': {
'en-US': 'Why use Harbor?',
'zh-CN': '为什么要使用Harbor'
},
'index_desc': {
'en-US': 'Project Harbor is to build an enterprise-class, reliable registry server. Enterprises can set up a private registry server in their own environment to improve productivity as well as security. Project Harbor can be used in both development and production environment.',
'zh-CN': 'Harbor是可靠的企业级Registry服务器。企业用户可使用Harbor搭建私有容器Registry服务提高生产效率和安全度既可应用于生产环境也可以在开发环境中使用。'
},
'index_desc_1': {
'en-US': 'Security: Keep their intellectual properties within their organizations.',
'zh-CN': '安全: 确保知识产权在自己组织内部的管控之下。'
},
'index_desc_2': {
'en-US': 'Efficiency: A private registry server is set up within the organization\'s network and can reduce significantly the internet traffic to the public service. ',
'zh-CN': '效率: 搭建组织内部的私有容器Registry服务可显著降低访问公共Registry服务的网络需求。'
},
'index_desc_3': {
'en-US': 'Access Control: RBAC (Role Based Access Control) is provided. User management can be integrated with existing enterprise identity services like AD/LDAP. ',
'zh-CN': '访问控制: 提供基于角色的访问控制,可集成企业目前拥有的用户管理系统(如:AD/LDAP。 '
},
'index_desc_4': {
'en-US': 'Audit: All access to the registry are logged and can be used for audit purpose.',
'zh-CN': '审计: 所有访问Registry服务的操作均被记录便于日后审计。'
},
'index_desc_5': {
'en-US': 'GUI: User friendly single-pane-of-glass management console.',
'zh-CN': '管理界面: 具有友好易用图形管理界面。'
},
'learn_more': {
'en-US': 'Learn more...',
'zh-CN': '更多...'
},
'repositories': {
'en-US': 'Repositories',
'zh-CN': '镜像仓库'
},
'project_repo_name': {
'en-US': 'Project/Repository Name',
'zh-CN': '项目/镜像仓库名称'
},
'creation_time': {
'en-US': 'Creation Time',
'zh-CN': '创建时间'
},
'author': {
'en-US': 'Author',
'zh-CN': '作者'
},
'username': {
'en-US': 'Username',
'zh-CN': '用户名'
},
'username_is_required' : {
'en-US': 'Username is required.',
'zh-CN': '用户名为必填项。'
},
'username_has_been_taken' : {
'en-US': 'Username has been taken.',
'zh-CN': '用户名已被占用。'
},
'username_is_too_long' : {
'en-US': 'Username is too long. (maximum 20 characters)',
'zh-CN': '用户名长度超出限制。最长为20个字符'
},
'username_contains_illegal_chars': {
'en-US': 'Username contains illegal character(s).',
'zh-CN': '用户名包含不合法的字符。'
},
'email': {
'en-US': 'Email',
'zh-CN': '邮箱'
},
'email_desc': {
'en-US': 'The Email address will be used for resetting password.',
'zh-CN': '此邮箱将用于重置密码。'
},
'email_is_required' : {
'en-US': 'Email is required.',
'zh-CN': '邮箱为必填项。'
},
'email_has_been_taken' : {
'en-US': 'Email has been taken.',
'zh-CN': '邮箱已被占用。'
},
'email_content_illegal' : {
'en-US': 'Email format is illegal.',
'zh-CN': '邮箱格式不合法。'
},
'email_does_not_exist' : {
'en-US': 'Email does not exist.',
'zh-CN': '邮箱不存在。'
},
'email_is_too_long': {
'en-US': 'Email is to long. (maximum 50 characters)',
'zh-CN': '邮箱名称长度超出限制。最长为50个字符'
},
'full_name': {
'en-US': 'Full Name',
'zh-CN': '全名'
},
'full_name_desc': {
'en-US': 'First name & Last name',
'zh-CN': '请输入全名。'
},
'full_name_is_required' : {
'en-US': 'Full name is required.',
'zh-CN': '全名为必填项。'
},
'full_name_is_too_long' : {
'en-US': 'Full name is too long. (maximum 20 characters)',
'zh-CN': '全名长度超出限制。最长为20个字符'
},
'full_name_contains_illegal_chars' : {
'en-US': 'Full name contains illegal character(s).',
'zh-CN': '全名包含不合法的字符。'
},
'password': {
'en-US': 'Password',
'zh-CN': '密码'
},
'password_desc': {
'en-US': 'At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.',
'zh-CN': '至少输入 7个字符且包含 1个小写字母 1个大写字母和 1个数字。'
},
'password_is_required' : {
'en-US': 'Password is required.',
'zh-CN': '密码为必填项。'
},
'password_is_invalid' : {
'en-US': 'Password is invalid. At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.',
'zh-CN': '密码无效。至少输入 7个字符且包含 1个小写字母1个大写字母和 1个数字。'
},
'confirm_password': {
'en-US': 'Confirm Password',
'zh-CN': '确认密码'
},
'password_does_not_match' : {
'en-US': 'Passwords do not match.',
'zh-CN': '两次密码输入不一致。'
},
'comments': {
'en-US': 'Comments',
'zh-CN': '备注'
},
'comment_is_too_long' : {
'en-US': 'Comment is too long. (maximum 20 characters)',
'zh-CN': '备注长度超出限制。最长为20个字符'
},
'forgot_password_description': {
'en-US': 'Please input the Email used when you signed up, a reset password Email will be sent to you.',
'zh-CN': '重置邮件将发送到此邮箱。'
},
'email_does_not_exist': {
'en-US': 'Email does not exist',
'zh-CN': '邮箱不存在。'
},
'reset_password': {
'en-US': 'Reset Password',
'zh-CN': '重置密码'
},
'summary': {
'en-US': 'Summary',
'zh-CN': '摘要'
},
'projects': {
'en-US': 'Projects',
'zh-CN': '项目'
},
'public_projects': {
'en-US': 'Public Projects',
'zh-CN': '公开项目'
},
'public': {
'en-US': 'Public',
'zh-CN': '公开'
},
'total_projects': {
'en-US': 'Total Projects',
'zh-CN': '全部项目'
},
'public_repositories': {
'en-US': 'Public Repositories',
'zh-CN': '公开镜像仓库'
},
'total_repositories': {
'en-US': 'Total Repositories',
'zh-CN': '全部镜像仓库'
},
'top_10_repositories': {
'en-US': 'Top 10 Repositories',
'zh-CN': 'Top 10 镜像仓库'
},
'repository_name': {
'en-US': 'Repository Name',
'zh-CN': '镜像仓库名'
},
'size': {
'en-US': 'Size',
'zh-CN': '规格'
},
'creator': {
'en-US': 'Creator',
'zh-CN': '创建者'
},
'logs': {
'en-US': 'Logs',
'zh-CN': '日志'
},
'task_name': {
'en-US': 'Task Name',
'zh-CN': '任务名称'
},
'details': {
'en-US': 'Details',
'zh-CN': '详细信息'
},
'user': {
'en-US': 'User',
'zh-CN': '用户'
},
'users': {
'en-US': 'Users',
'zh-CN': '用户'
},
'my_projects': {
'en-US': 'My Projects',
'zh-CN': '我的项目'
},
'project_name': {
'en-US': 'Project Name',
'zh-CN': '项目名称'
},
'role': {
'en-US': 'Role',
'zh-CN': '角色'
},
'publicity': {
'en-US': 'Publicity',
'zh-CN': '公开'
},
'button_on': {
'en-US': 'On',
'zh-CN': '打开'
},
'button_off': {
'en-US': 'Off',
'zh-CN': '关闭'
},
'new_project': {
'en-US': 'New Project',
'zh-CN': '新增项目'
},
'save': {
'en-US': 'Save',
'zh-CN': '保存'
},
'cancel': {
'en-US': 'Cancel',
'zh-CN': '取消'
},
'items': {
'en-US': 'items',
'zh-CN': '条记录'
},
'add_member': {
'en-US': 'Add Member',
'zh-CN': '新增成员'
},
'operation': {
'en-US': 'Operation',
'zh-CN': '操作'
},
'advanced_search': {
'en-US': 'Advanced Search',
'zh-CN': '高级搜索'
},
'all': {
'en-US': 'All',
'zh-CN': '全部'
},
'others': {
'en-US': 'Others',
'zh-CN': '其他'
},
'search': {
'en-US': 'Search',
'zh-CN': '搜索'
},
'duration': {
'en-US': 'Duration',
'zh-CN': '持续时间'
},
'from': {
'en-US': 'From',
'zh-CN': '起始'
},
'to': {
'en-US': 'To',
'zh-CN': '结束'
},
'timestamp': {
'en-US': 'Timestamp',
'zh-CN': '时间戳'
},
'dashboard': {
'en-US': 'Dashboard',
'zh-CN': '消息中心'
},
'admin_options': {
'en-US': 'Admin Options',
'zh-CN': '管理员选项'
},
'account_setting': {
'en-US': 'Account Setting',
'zh-CN': '个人设置'
},
'log_out': {
'en-US': 'Log Out',
'zh-CN': '注销'
},
'registration_time': {
'en-US': 'Registration Time',
'zh-CN': '注册时间'
},
'system_management': {
'en-US': 'System Management',
'zh-CN': '系统管理'
},
'change_password': {
'en-US': 'Change Password',
'zh-CN': '修改密码'
},
'old_password': {
'en-US': 'Old Password',
'zh-CN': '原密码'
},
'old_password_is_required': {
'en-US': 'Old password is required.',
'zh-CN': '原密码为必填项。'
},
'old_password_is_incorrect': {
'en-US': 'Old password is incorrect.',
'zh-CN': '原密码不正确。'
},
'new_password_is_required': {
'en-US': 'New password is required.',
'zh-CN': '新密码为必填项。'
},
'new_password_is_invalid': {
'en-US': 'New password is invalid. At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.',
'zh-CN': '新密码无效。至少输入 7个字符且包含 1个小写字母1个大写字母和 1个数字。'
},
'new_password': {
'en-US': 'New Password',
'zh-CN': '新密码'
},
'username_already_exist': {
'en-US': 'Username already exist.',
'zh-CN': '用户名已存在。'
},
'username_does_not_exist': {
'en-US': 'Username does not exist.',
'zh-CN': '用户名不存在。'
},
'username_or_password_is_incorrect': {
'en-US': 'Username or password is incorrect',
'zh-CN': '用户名或密码不正确。'
},
'username_email': {
'en-US': 'Username/Email',
'zh-CN': '用户名/邮箱'
},
'project_name_is_required': {
'en-US': 'Project name is required',
'zh-CN': '项目名称为必填项。'
},
'project_already_exist': {
'en-US': 'Project already exist',
'zh-CN': '项目已存在。'
},
'project_name_is_invalid': {
'en-US': 'Project name is invalid',
'zh-CN': '项目名称无效。'
},
'projects_or_repositories': {
'en-US': 'Projects or repositories',
'zh-CN': '项目和镜像资源'
},
'tag': {
'en-US': 'Tag',
'zh-CN': '标签'
},
'image_details': {
'en-US': 'Image Details',
'zh-CN': '镜像明细'
},
'pull_command': {
'en-US': 'Pull Command',
'zh-CN': 'Pull 命令'
},
'alert_delete_repo_title': {
'en-US': 'Delete repository - $0',
'zh-CN': '删除镜像仓库 - $0'
},
'alert_delete_repo': {
'en-US': 'After deleting the associated tags with the repository will be deleted together.<br/>' +
'And the corresponding image will be removed from the system.<br/>' +
'<br/>Delete this "$0" repository now?',
'zh-CN': '删除镜像仓库也会删除其所有相关联的镜像标签,<br/>并且其对应镜像资源文件也会被从系统删除。<br/>' +
'<br/>是否删除镜像仓库 "$0" ?'
},
'alert_delete_last_tag': {
'en-US': 'After deleting the associated repository with the tag will be deleted together,<br/>' +
'because a repository contains at least one tag. And the corresponding image will be removed from the system.<br/>' +
'<br/>Delete this "$0" tag now?',
'zh-CN': '当删除只包含一个镜像标签的镜像仓库时,其对应的镜像仓库也会被从系统中删除。<br/>' +
'<br/>删除镜像标签 "$0" ?'
},
'alert_delete_tag_title': {
'en-US': 'Delete tag - $0',
'zh-CN': '删除镜像标签 - $0'
},
'alert_delete_tag': {
'en-US': 'Delete this "$0" tag now?',
'zh-CN': '删除镜像标签 "$0" ?'
},
'close': {
'en-US': 'Close',
'zh-CN': '关闭'
},
'ok': {
'en-US': 'OK',
'zh-CN': '确认'
}
};

View File

@ -0,0 +1,121 @@
var locale_messages = {
'sign_in': 'Sign In',
'sign_up': 'Sign Up',
'forgot_password': 'Forgot Password',
'login_now': 'Login Now',
'its_easy_to_get_started': 'It\'s easy to get started ...',
'anybody_can_read_public_projects': 'Anybody can read public projects',
'create_projects_and_connect_repositories': 'Create projects and connect repositories',
'user_management_and_role_assignment': 'User management and role assignment',
'why_use_harbor': 'Why use Harbor?',
'index_desc': 'Project Harbor is to build an enterprise-class, reliable registry server. Enterprises can set up a private registry server in their own environment to improve productivity as well as security. Project Harbor can be used in both development and production environment.',
'index_desc_1': 'Security: Keep their intellectual properties within their organizations.',
'index_desc_2': 'Efficiency: A private registry server is set up within the organization\'s network and can reduce significantly the internet traffic to the public service. ',
'index_desc_3': 'Access Control: RBAC (Role Based Access Control) is provided. User management can be integrated with existing enterprise identity services like AD/LDAP. ',
'index_desc_4': 'Audit: All access to the registry are logged and can be used for audit purpose.',
'index_desc_5': 'GUI: User friendly single-pane-of-glass management console.',
'learn_more': 'Learn more...',
'repositories': 'Repositories',
'project_repo_name': 'Project/Repository Name',
'creation_time': 'Creation Time',
'author': 'Author',
'username': 'Username',
'username_is_required': 'Username is required.',
'username_has_been_taken': 'Username has been taken.',
'username_is_too_long': 'Username is too long. (maximum 20 characters)',
'username_contains_illegal_chars': 'Username contains illegal character(s).',
'email': 'Email',
'email_desc': 'The Email address will be used for resetting password.',
'email_is_required': 'Email is required.',
'email_has_been_taken': 'Email has been taken.',
'email_content_illegal': 'Email format is illegal.',
'email_does_not_exist': 'Email does not exist.',
'email_is_too_long': 'Email is to long. (maximum 50 characters)',
'full_name': 'Full Name',
'full_name_desc': 'First name & Last name',
'full_name_is_required': 'Full name is required.',
'full_name_is_too_long': 'Full name is too long. (maximum 20 characters)',
'full_name_contains_illegal_chars': 'Full name contains illegal character(s).',
'password': 'Password',
'password_desc': 'At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.',
'password_is_required': 'Password is required.',
'password_is_invalid': 'Password is invalid. At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.',
'confirm_password': 'Confirm Password',
'password_does_not_match': 'Passwords do not match.',
'comments': 'Comments',
'comment_is_too_long': 'Comment is too long. (maximum 20 characters)',
'forgot_password_description': 'Please input the Email used when you signed up, a reset password Email will be sent to you.',
'email_does_not_exist': 'Email does not exist',
'reset_password': 'Reset Password',
'summary': 'Summary',
'projects': 'Projects',
'public_projects': 'Public Projects',
'public': 'Public',
'total_projects': 'Total Projects',
'public_repositories': 'Public Repositories',
'total_repositories': 'Total Repositories',
'top_10_repositories': 'Top 10 Repositories',
'repository_name': 'Repository Name',
'size': 'Size',
'creator': 'Creator',
'logs': 'Logs',
'task_name': 'Task Name',
'details': 'Details',
'user': 'User',
'users': 'Users',
'my_projects': 'My Projects',
'project_name': 'Project Name',
'role': 'Role',
'publicity': 'Publicity',
'button_on': 'On',
'button_off': 'Off',
'new_project': 'New Project',
'save': 'Save',
'cancel': 'Cancel',
'items': 'items',
'add_member': 'Add Member',
'operation': 'Operation',
'advanced_search': 'Advanced Search',
'all': 'All',
'others': 'Others',
'search': 'Search',
'duration': 'Duration',
'from': 'From',
'to': 'To',
'timestamp': 'Timestamp',
'dashboard': 'Dashboard',
'admin_options': 'Admin Options',
'account_setting': 'Account Setting',
'log_out': 'Log Out',
'registration_time': 'Registration Time',
'system_management': 'System Management',
'change_password': 'Change Password',
'old_password': 'Old Password',
'old_password_is_required': 'Old password is required.',
'old_password_is_incorrect': 'Old password is incorrect.',
'new_password_is_required': 'New password is required.',
'new_password_is_invalid': 'New password is invalid. At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.',
'new_password': 'New Password',
'username_already_exist': 'Username already exist.',
'username_does_not_exist': 'Username does not exist.',
'username_or_password_is_incorrect': 'Username or password is incorrect',
'username_email': 'Username/Email',
'project_name_is_required': 'Project name is required',
'project_already_exist': 'Project already exist',
'project_name_is_invalid': 'Project name is invalid',
'projects_or_repositories': 'Projects or repositories',
'tag': 'Tag',
'image_details': 'Image Details',
'pull_command': 'Pull Command',
'alert_delete_repo_title': 'Delete repository - $0',
'alert_delete_repo': 'After deleting the associated tags with the repository will be deleted together.<br/>' +
'And the corresponding image will be removed from the system.<br/>' +
'<br/>Delete this "$0" repository now?',
'alert_delete_last_tag': 'After deleting the associated repository with the tag will be deleted together,<br/>' +
'because a repository contains at least one tag. And the corresponding image will be removed from the system.<br/>' +
'<br/>Delete this "$0" tag now?',
'alert_delete_tag_title': 'Delete tag - $0',
'alert_delete_tag': 'Delete this "$0" tag now?',
'close': 'Close',
'ok': 'OK'
};

View File

@ -0,0 +1,119 @@
var locale_messages = {
'sign_in': '登录',
'sign_up': '注册',
'forgot_password': '忘记密码',
'login_now': '立刻登录',
'its_easy_to_get_started': '这很容易上手...',
'anybody_can_read_public_projects': '任何人都可以访问公开的项目',
'create_projects_and_connect_repositories': '创建项目并关联镜像仓库',
'user_management_and_role_assignment': '用户管理和角色分派',
'why_use_harbor': '为什么要使用Harbor',
'index_desc': 'Harbor是可靠的企业级Registry服务器。企业用户可使用Harbor搭建私有容器Registry服务提高生产效率和安全度既可应用于生产环境也可以在开发环境中使用。',
'index_desc_1': '安全: 确保知识产权在自己组织内部的管控之下。',
'index_desc_2': '效率: 搭建组织内部的私有容器Registry服务可显著降低访问公共Registry服务的网络需求。',
'index_desc_3': '访问控制: 提供基于角色的访问控制,可集成企业目前拥有的用户管理系统(如:AD/LDAP。',
'index_desc_4': '审计: 所有访问Registry服务的操作均被记录便于日后审计。',
'index_desc_5': '管理界面: 具有友好易用图形管理界面。',
'learn_more': '更多...',
'repositories': '镜像仓库',
'project_repo_name': '项目/镜像仓库名称',
'creation_time': '创建时间',
'author': '作者',
'username': '用户名',
'username_is_required' : '用户名为必填项。',
'username_has_been_taken' : '用户名已被占用。',
'username_is_too_long' : '用户名长度超出限制。最长为20个字符',
'username_contains_illegal_chars': '用户名包含不合法的字符。',
'email': '邮箱',
'email_desc': '此邮箱将用于重置密码。',
'email_is_required' : '邮箱为必填项。',
'email_has_been_taken' : '邮箱已被占用。',
'email_content_illegal' : '邮箱格式不合法。',
'email_does_not_exist' : '邮箱不存在。',
'email_is_too_long': '邮箱名称长度超出限制。最长为50个字符',
'full_name': '全名',
'full_name_desc': '请输入全名。',
'full_name_is_required' : '全名为必填项。',
'full_name_is_too_long' : '全名长度超出限制。最长为20个字符',
'full_name_contains_illegal_chars' : '全名包含不合法的字符。',
'password': '密码',
'password_desc': '至少输入 7个字符且包含 1个小写字母 1个大写字母和 1个数字。',
'password_is_required' : '密码为必填项。',
'password_is_invalid' : '密码无效。至少输入 7个字符且包含 1个小写字母1个大写字母和 1个数字。',
'confirm_password': '确认密码',
'password_does_not_match' : '两次密码输入不一致。',
'comments': '备注',
'comment_is_too_long' : '备注长度超出限制。最长为20个字符',
'forgot_password_description': '重置邮件将发送到此邮箱。',
'email_does_not_exist': '邮箱不存在。',
'reset_password': '重置密码',
'summary': '摘要',
'projects': '项目',
'public_projects': '公开项目',
'public': '公开',
'total_projects': '全部项目',
'public_repositories': '公开镜像仓库',
'total_repositories': '全部镜像仓库',
'top_10_repositories': 'Top 10 镜像仓库',
'repository_name': '镜像仓库名',
'size': '规格',
'creator': '创建者',
'logs': '日志',
'task_name': '任务名称',
'details': '详细信息',
'user': '用户',
'users': '用户',
'my_projects': '我的项目',
'project_name': '项目名称',
'role': '角色',
'publicity': '公开',
'button_on': '打开',
'button_off': '关闭',
'new_project': '新增项目',
'save': '保存',
'cancel': '取消',
'items': '条记录',
'add_member': '新增成员',
'operation': '操作',
'advanced_search': '高级搜索',
'all': '全部',
'others': '其他',
'search':'搜索',
'duration': '持续时间',
'from': '起始',
'to': '结束',
'timestamp': '时间戳',
'dashboard': '消息中心',
'admin_options': '管理员选项',
'account_setting': '个人设置',
'log_out': '注销',
'registration_time': '注册时间',
'system_management': '系统管理',
'change_password': '修改密码',
'old_password': '原密码',
'old_password_is_required': '原密码为必填项。',
'old_password_is_incorrect': '原密码不正确。',
'new_password_is_required': '新密码为必填项。',
'new_password_is_invalid': '新密码无效。至少输入 7个字符且包含 1个小写字母1个大写字母和 1个数字。',
'new_password': '新密码',
'username_already_exist': '用户名已存在。',
'username_does_not_exist': '用户名不存在。',
'username_or_password_is_incorrect': '用户名或密码不正确。',
'username_email': '用户名/邮箱',
'project_name_is_required': '项目名称为必填项。',
'project_already_exist': '项目已存在。',
'project_name_is_invalid': '项目名称无效。',
'projects_or_repositories': '项目和镜像资源',
'tag': '标签',
'image_details': '镜像明细',
'pull_command': 'Pull 命令',
'alert_delete_repo_title': '删除镜像仓库 - $0',
'alert_delete_repo': '删除镜像仓库也会删除其所有相关联的镜像标签,<br/>并且其对应镜像资源文件也会被从系统删除。<br/>' +
'<br/>是否删除镜像仓库 "$0" ?',
'alert_delete_last_tag': '当删除只包含一个镜像标签的镜像仓库时,其对应的镜像仓库也会被从系统中删除。<br/>' +
'<br/>删除镜像标签 "$0" ?',
'alert_delete_tag_title': '删除镜像标签 - $0',
'alert_delete_tag': '删除镜像标签 "$0" ?',
'close': '关闭',
'ok': '确认'
};

View File

@ -9,29 +9,48 @@
I18nService.$inject = ['$cookies', '$window'];
function I18nService($cookies, $window) {
var languages = $.extend(true, {}, global_messages);
var cookieOptions = {'path': '/'};
var messages = $.extend(true, {}, eval('locale_messages'));
var defaultLanguage = navigator.language || 'en-US';
var languageNames = {
var supportLanguages = {
'en-US': 'English',
'zh-CN': '中文'
};
};
var isSupportLanguage = function(language) {
for (var i in supportLanguages) {
if(language == i) {
return true;
}
}
return false;
}
return tr;
function tr() {
return {
'setCurrentLanguage': function(language) {
if(!language){
'setCurrentLanguage': function(language) {
if(!angular.isDefined(language) || !isSupportLanguage(language)) {
language = defaultLanguage;
}
$cookies.put('language', language, {'path': '/'});
$cookies.put('language', language, cookieOptions);
},
'setDefaultLanguage': function() {
$cookies.put('language', defaultLanguage, cookieOptions);
},
'getCurrentLanguage': function() {
return $cookies.get('language') || defaultLanguage;
},
'getLanguageName': function(crrentLanguage) {
return languageNames[crrentLanguage];
'getLanguageName': function(language) {
if(!angular.isDefined(language) || !isSupportLanguage(language)) {
language = defaultLanguage;
}
return supportLanguages[language];
},
'getValue': function(key, currentLanguage) {
return languages[key][currentLanguage];
'unset': function(){
$cookies.put('language', defaultLanguage, cookieOptions);
},
'getValue': function(key) {
return messages[key];
}
}
}

View File

@ -6,20 +6,20 @@
.module('harbor.session')
.controller('CurrentUserController', CurrentUserController);
CurrentUserController.$inject = ['CurrentUserService', 'currentUser', '$scope', '$timeout', '$window'];
CurrentUserController.$inject = ['CurrentUserService', 'currentUser', '$window'];
function CurrentUserController(CurrentUserService, currentUser, $scope, $timeout, $window) {
function CurrentUserController(CurrentUserService, currentUser, $window) {
var vm = this;
if(!angular.isDefined(currentUser.get())) {
CurrentUserService()
.then(getCurrentUserComplete)
.catch(getCurrentUserFailed);
}
CurrentUserService()
.then(getCurrentUserComplete)
.catch(getCurrentUserFailed);
function getCurrentUserComplete(response) {
currentUser.set(response.data);
if(angular.isDefined(response)) {
currentUser.set(response.data);
}
}
function getCurrentUserFailed(e){

View File

@ -17,9 +17,11 @@ func initNgRouters() {
beego.Router("/ng/forgot_password", &ng.ForgotPasswordController{})
beego.Router("/ng/reset_password", &ng.ResetPasswordController{})
beego.Router("/ng/search", &ng.SearchController{})
beego.Router("/ng/log_out", &ng.CommonController{}, "get:LogOut")
beego.Router("/ng/reset", &ng.CommonController{}, "post:ResetPassword")
beego.Router("/ng/sendEmail", &ng.CommonController{}, "get:SendEmail")
beego.Router("/ng/language", &ng.CommonController{}, "get:SwitchLanguage")
beego.Router("/ng/optional_menu", &ng.OptionalMenuController{})
beego.Router("/ng/navigation_header", &ng.NavigationHeaderController{})

View File

@ -38,7 +38,7 @@
<div class="container">
<div class="row row-custom">
<div class="col-xs-12 col-md-12">
<div class="down-section single">
<div class="down-section">
<h4 class="page-header title-color underlined">// 'logs' | tr //</h4>
<div style="padding: 15px;">
<table class="table">

View File

@ -5,7 +5,7 @@
<h1 class="col-md-12 col-md-offset-2 main-title title-color">// 'forgot_password' | tr //</h1>
<div class="row">
<div class="col-md-12 col-md-offset-2 main-content">
<form name="form" class="form-horizontal css-form" ng-submit="form.$valid " >
<form name="form" class="form-horizontal css-form" ng-submit="form.$valid" >
<div class="form-group">
<label for="email" class="col-sm-3 control-label">// 'email' | tr //:</label>
<div class="col-sm-7">

View File

@ -8,8 +8,9 @@
<li class="dropdown-submenu">
<a tabindex="-1" href="#"><span class="glyphicon glyphicon-globe"></span> //vm.languageName//</a>
<ul class="dropdown-menu">
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('en-US')">English</a></li>
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('zh-CN')">中文</a></li>
{{ range $key, $value := .SupportLanguages }}
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('{{ $key }}')">{{ $value.Name }}</a></li>
{{ end }}
</ul>
</li>
<li class="divider"></li>
@ -22,8 +23,9 @@
<span class="glyphicon glyphicon-globe"></span> //vm.languageName//
</a>
<ul class="dropdown-menu multi-level" role="menu" aria-labelledby="dropdownMenu">
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('en-US')">English</a></li>
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('zh-CN')">中文</a></li>
{{ range $key, $value := .SupportLanguages }}
<li><a href="javascript:void(0);" ng-click="vm.setLanguage('{{ $key }}')">{{ $value.Name }}</a></li>
{{ end }}
</ul>
</div>
{{ end }}

View File

@ -98,7 +98,13 @@
<script src="/static/ng/resources/js/layout/search/search.controller.js"></script>
<script src="/static/ng/resources/js/services/i18n/services.i18n.module.js"></script>
<script src="/static/ng/resources/js/services/i18n/locale_messages.js"></script>
{{ if eq .Lang "zh-CN" }}
<script src="/static/ng/resources/js/services/i18n/locale_messages_zh-CN.js"></script>
{{ else if eq .Lang "en-US"}}
<script src="/static/ng/resources/js/services/i18n/locale_messages_en-US.js"></script>
{{ end }}
<script src="/static/ng/resources/js/services/i18n/services.i18n.js"></script>
<script src="/static/ng/resources/js/services/search/services.search.module.js"></script>

View File

@ -5,7 +5,7 @@
<h1 class="col-md-12 col-md-offset-2 main-title title-color">// 'sign_up' | tr //</h1>
<div class="row">
<div class="col-md-12 col-md-offset-2 main-content">
<form name="form" class="form-horizontal css-form" ng-submit="form.$valid" novalidate>
<form name="form" class="form-horizontal css-form" ng-submit="form.$valid">
<div class="form-group">
<label for="username" class="col-sm-3 control-label">// 'username' | tr //:</label>
<div class="col-sm-7">