diff --git a/Deploy/templates/ui/app.conf b/Deploy/templates/ui/app.conf index 090bcdc47..6d8f15728 100644 --- a/Deploy/templates/ui/app.conf +++ b/Deploy/templates/ui/app.conf @@ -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 diff --git a/controllers/ng/base.go b/controllers/ng/base.go index c0eb02c54..3b0b94fc6 100644 --- a/controllers/ng/base.go +++ b/controllers/ng/base.go @@ -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") diff --git a/controllers/ng/password.go b/controllers/ng/password.go index 9b16bba93..f6f169c4a 100644 --- a/controllers/ng/password.go +++ b/controllers/ng/password.go @@ -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 diff --git a/static/ng/resources/css/dashboard.css b/static/ng/resources/css/dashboard.css index 215e5dc27..aac91bac8 100644 --- a/static/ng/resources/css/dashboard.css +++ b/static/ng/resources/css/dashboard.css @@ -12,7 +12,3 @@ text-align: left; } -.single { - margin-right: 0; -} - diff --git a/static/ng/resources/js/components/optional-menu/optional-menu.directive.js b/static/ng/resources/js/components/optional-menu/optional-menu.directive.js index 37f57650b..8d30ee06c 100644 --- a/static/ng/resources/js/components/optional-menu/optional-menu.directive.js +++ b/static/ng/resources/js/components/optional-menu/optional-menu.directive.js @@ -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) { diff --git a/static/ng/resources/js/components/sign-in/sign-in.directive.html b/static/ng/resources/js/components/sign-in/sign-in.directive.html index 4b62997ab..a293a5f84 100644 --- a/static/ng/resources/js/components/sign-in/sign-in.directive.html +++ b/static/ng/resources/js/components/sign-in/sign-in.directive.html @@ -3,7 +3,7 @@
-
+
// 'username_is_required' | tr //
@@ -13,7 +13,7 @@
-
+
// 'password_is_required' | tr //
// vm.errorMessage | tr // diff --git a/static/ng/resources/js/services/i18n/locale_messages.js b/static/ng/resources/js/services/i18n/locale_messages.js deleted file mode 100644 index 1ddfc87b2..000000000 --- a/static/ng/resources/js/services/i18n/locale_messages.js +++ /dev/null @@ -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.
' + - 'And the corresponding image will be removed from the system.
' + - '
Delete this "$0" repository now?', - 'zh-CN': '删除镜像仓库也会删除其所有相关联的镜像标签,
并且其对应镜像资源文件也会被从系统删除。
' + - '
是否删除镜像仓库 "$0" ?' - }, - 'alert_delete_last_tag': { - 'en-US': 'After deleting the associated repository with the tag will be deleted together,
' + - 'because a repository contains at least one tag. And the corresponding image will be removed from the system.
' + - '
Delete this "$0" tag now?', - 'zh-CN': '当删除只包含一个镜像标签的镜像仓库时,其对应的镜像仓库也会被从系统中删除。
' + - '
删除镜像标签 "$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': '确认' - } -}; \ No newline at end of file diff --git a/static/ng/resources/js/services/i18n/locale_messages_en-US.js b/static/ng/resources/js/services/i18n/locale_messages_en-US.js new file mode 100644 index 000000000..1b95db666 --- /dev/null +++ b/static/ng/resources/js/services/i18n/locale_messages_en-US.js @@ -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.
' + + 'And the corresponding image will be removed from the system.
' + + '
Delete this "$0" repository now?', + 'alert_delete_last_tag': 'After deleting the associated repository with the tag will be deleted together,
' + + 'because a repository contains at least one tag. And the corresponding image will be removed from the system.
' + + '
Delete this "$0" tag now?', + 'alert_delete_tag_title': 'Delete tag - $0', + 'alert_delete_tag': 'Delete this "$0" tag now?', + 'close': 'Close', + 'ok': 'OK' +}; \ No newline at end of file diff --git a/static/ng/resources/js/services/i18n/locale_messages_zh-CN.js b/static/ng/resources/js/services/i18n/locale_messages_zh-CN.js new file mode 100644 index 000000000..f854d5fd4 --- /dev/null +++ b/static/ng/resources/js/services/i18n/locale_messages_zh-CN.js @@ -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': '删除镜像仓库也会删除其所有相关联的镜像标签,
并且其对应镜像资源文件也会被从系统删除。
' + + '
是否删除镜像仓库 "$0" ?', + 'alert_delete_last_tag': '当删除只包含一个镜像标签的镜像仓库时,其对应的镜像仓库也会被从系统中删除。
' + + '
删除镜像标签 "$0" ?', + 'alert_delete_tag_title': '删除镜像标签 - $0', + 'alert_delete_tag': '删除镜像标签 "$0" ?', + 'close': '关闭', + 'ok': '确认' +}; \ No newline at end of file diff --git a/static/ng/resources/js/services/i18n/services.i18n.js b/static/ng/resources/js/services/i18n/services.i18n.js index d34a5c672..00b5ced18 100644 --- a/static/ng/resources/js/services/i18n/services.i18n.js +++ b/static/ng/resources/js/services/i18n/services.i18n.js @@ -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]; } } } diff --git a/static/ng/resources/js/session/session.current-user.js b/static/ng/resources/js/session/session.current-user.js index 9f92b6751..e50406cb9 100644 --- a/static/ng/resources/js/session/session.current-user.js +++ b/static/ng/resources/js/session/session.current-user.js @@ -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){ diff --git a/ui/ngrouter.go b/ui/ngrouter.go index f28ff4d45..3e6a0730e 100644 --- a/ui/ngrouter.go +++ b/ui/ngrouter.go @@ -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{}) diff --git a/views/ng/dashboard.htm b/views/ng/dashboard.htm index 9dcdbcf8c..9b1a8727e 100644 --- a/views/ng/dashboard.htm +++ b/views/ng/dashboard.htm @@ -38,7 +38,7 @@
-
+
diff --git a/views/ng/forgot-password.htm b/views/ng/forgot-password.htm index c1bafd819..e8d02cc7e 100644 --- a/views/ng/forgot-password.htm +++ b/views/ng/forgot-password.htm @@ -5,7 +5,7 @@

// 'forgot_password' | tr //

-
+
diff --git a/views/ng/optional-menu.htm b/views/ng/optional-menu.htm index 9aabee197..f7512665e 100644 --- a/views/ng/optional-menu.htm +++ b/views/ng/optional-menu.htm @@ -8,8 +8,9 @@
  • @@ -22,8 +23,9 @@ //vm.languageName//
    {{ end }} \ No newline at end of file diff --git a/views/ng/sections/header-include.htm b/views/ng/sections/header-include.htm index 00673eb57..0d3d5b738 100644 --- a/views/ng/sections/header-include.htm +++ b/views/ng/sections/header-include.htm @@ -98,7 +98,13 @@ - + +{{ if eq .Lang "zh-CN" }} + +{{ else if eq .Lang "en-US"}} + +{{ end }} + diff --git a/views/ng/sign-up.htm b/views/ng/sign-up.htm index d2955baf5..312629dea 100644 --- a/views/ng/sign-up.htm +++ b/views/ng/sign-up.htm @@ -5,7 +5,7 @@

    // 'sign_up' | tr //

    - +