diff --git a/AUTHORS b/AUTHORS index e03722c33c..f2416e0c0a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -5,6 +5,7 @@ Alexey Erkak Allen Heavey Amanda Zhang Benniu Ji +Bin Liu Bobby Zhang Chaofeng Wu Daniel Jiang diff --git a/Deploy/templates/ui/app.conf b/Deploy/templates/ui/app.conf index 090bcdc471..f75b673c86 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|de-DE|ru-RU|ja-JP +names = en-US|zh-CN|de-DE|ru-RU|ja-JP [dev] httpport = 80 diff --git a/README.md b/README.md index 479707edd4..1d76c2964e 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Project Harbor is an enterprise-class registry server, which extends the open so * **Graphical user portal**: User can easily browse, search Docker repositories, manage projects/namespaces. * **AD/LDAP support**: Harbor integrates with existing enterprise AD/LDAP for user authentication and management. * **Auditing**: All the operations to the repositories are tracked. -* **Internationalization**: Already localized for English, Chinese, German and Russian. More languages can be added. +* **Internationalization**: Already localized for English, Chinese, German, Japanese and Russian. More languages can be added. * **RESTful API**: RESTful APIs for most administrative operations, easing intergration with external management platforms. ### Getting Started @@ -67,7 +67,7 @@ Harbor is available under the [Apache 2 license](LICENSE).     CaiCloud ### Users -MaDaiLiCai +MaDaiLiCai Dianrong ### Supporting Technologies beego Harbor is powered by Beego, an open source framework to build and develop applications in the Go way. diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000000..ed4e382c05 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,47 @@ +## Harbor Roadmap + +### About this document + +This document provides description of items that are gathered from the community and planned in Harbor's roadmap. This should serve as a reference point for Harbor users and contributors to understand where the project is heading, and help determine if a contribution could be conflicting with a longer term plan. + +### How to help? + +Discussion on the roadmap can take place in threads under [Issues](https://github.com/vmware/harbor/issues). Please open and comment on an issue if you want to provide suggestions and feedback to an item in the roadmap. Please review the roadmap to avoid potential duplicated effort. + +### How to add an item to the roadmap? +Please open an issue to track any initiative on the roadmap of Harbor. We will work with and rely on our community to focus our efforts to improve Harbor. + + +--- + + +### 1. Image replication between Harbor instances +Enable images to be replicated between two or more Harbor instances. This is useful to have multiple registry servers servicing a large cluster of nodes, or have distributed registry instances with identical images. + +### 2. Image deletion and garbage collection +a) Images can be deleted from UI. The files of deleted images are not removed immediately. + +b) The files of deleted images are recycled by an administrator during system maintenance(Garbage collection). The registry service must be shut down during the process of garbage collection. + + +### 3. Authentication (OAuth2) +In addition to LDAP/AD and local users, OAuth 2.0 can be used to authenticate a user. + +### 4. High Availability +Support multi-node deployment of Harbor for high availability, scalability and load-balancing purposes. + +### 5. Statistics and description for repositories +User can add a description to a repository. The access count of a repo can be aggregated and displayed. + + +### 6. Audit all operations in the system +Currently only image related operations are logged. Other operations in Harbor, such as user creation/deletion, role changes, password reset, should be tracked as well. + + +### 7. Migration tool to move from an existing registry to Harbor +A tool to migrate images from a vanilla registry server to Harbor, without the need to export/import a large amount of data. + + +### 8. Support API versioning +Provide versioning of Harbor's API. + diff --git a/controllers/login.go b/controllers/login.go index 2bfb299837..d608f8fbb2 100644 --- a/controllers/login.go +++ b/controllers/login.go @@ -69,7 +69,7 @@ func (c *CommonController) Login() { // SwitchLanguage handles UI request to switch between different languages and re-render template based on language. func (c *CommonController) SwitchLanguage() { lang := c.GetString("lang") - if lang == "en-US" || lang == "zh-CN" || lang == "de-DE" || lang == "ru-RU" { + if lang == "en-US" || lang == "zh-CN" || lang == "de-DE" || lang == "ru-RU" || lang == "ja-JP" { c.SetSession("lang", lang) c.Data["Lang"] = lang } diff --git a/docs/img/dianrong.png b/docs/img/dianrong.png new file mode 100644 index 0000000000..08f3cf2c8f Binary files /dev/null and b/docs/img/dianrong.png differ diff --git a/migration/README.md b/migration/README.md index dde8e00c9c..ee1b12dcba 100644 --- a/migration/README.md +++ b/migration/README.md @@ -1,54 +1,56 @@ -# migration -Migration is a module for migrating database schema between different version of project [harbor](https://github.com/vmware/harbor) +# Migration guide +Migration is a module for migrating database schema between different version of project [Harbor](https://github.com/vmware/harbor) + +This module is for those machine running Harbor's old version, such as 0.1.0. If your Harbor' version is up to date, please ignore this module. **WARNING!!** You must backup your data before migrating -###installation -- step 1: modify migration.cfg +###Installation +- step 1: change `db_username`, `db_password`, `db_port`, `db_name` in migration.cfg - step 2: build image from dockerfile ``` cd harbor-migration - docker build -t your-image-name . + docker build -t migrate-tool . ``` -###migration operation -- show instruction of harbor-migration - - ```docker run your-image-name help``` - -- test mysql connection in harbor-migration - - ```docker run -v /data/database:/var/lib/mysql your-image-name test``` - -- create backup file in `/path/to/backup` - - ``` - docker run -ti -v /data/database:/var/lib/mysql -v /path/to/backup:/harbor-migration/backup your-image-name backup - ``` - -- restore from backup file in `/path/to/backup` - - ``` - docker run -ti -v /data/database:/var/lib/mysql -v /path/to/backup:/harbor-migration/backup your-image-name restore - ``` - -- perform database schema upgrade - - ```docker run -ti -v /data/database:/var/lib/mysql your-image-name up head``` - -you can use `-v /etc/localtime:/etc/localtime` to sync container timezone with host timezone. - -you may change `/data/database` to the mysql volumes path you set in docker-compose.yml. -###migration step -- step 1: stop and remove harbor service +###Migrate Step +- step 1: stop and remove Harbor service ``` docker-compose down ``` -- step 2: perform migration operation -- step 3: rebuild newest harbor images and restart service +- step 2: create backup file in `/path/to/backup` + + ``` + docker run -ti --rm -v /data/database:/var/lib/mysql -v /path/to/backup:/harbor-migration/backup migrate-tool backup + ``` + +- step 3: perform database schema upgrade + + ```docker run -ti --rm -v /data/database:/var/lib/mysql migrate-tool up head``` + + + +- step 4: rebuild newest Harbor images and restart service ``` docker-compose build && docker-compose up -d ``` + +You may change `/data/database` to the mysql volumes path you set in docker-compose.yml. + +###Migration operation reference +- You can use `help` to show instruction of Harbor migration + + ```docker run migrate-tool help``` + +- You can use `test` to test mysql connection in Harbor migration + + ```docker run --rm -v /data/database:/var/lib/mysql migrate-tool test``` + +- You can restore from backup file in `/path/to/backup` + + ``` + docker run -ti --rm -v /data/database:/var/lib/mysql -v /path/to/backup:/harbor-migration/backup migrate-tool restore + ``` diff --git a/migration/db_meta.py b/migration/db_meta.py index e20dd924cb..dcbdd4311d 100644 --- a/migration/db_meta.py +++ b/migration/db_meta.py @@ -4,6 +4,7 @@ import sqlalchemy as sa from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, relationship +from sqlalchemy.dialects import mysql Base = declarative_base() @@ -20,8 +21,8 @@ class User(Base): reset_uuid = sa.Column(sa.String(40)) salt = sa.Column(sa.String(40)) sysadmin_flag = sa.Column(sa.Integer) - creation_time = sa.Column(sa.DateTime) - update_time = sa.Column(sa.DateTime) + creation_time = sa.Column(mysql.TIMESTAMP) + update_time = sa.Column(mysql.TIMESTAMP) class Properties(Base): __tablename__ = 'properties' @@ -35,8 +36,8 @@ class ProjectMember(Base): project_id = sa.Column(sa.Integer(), primary_key = True) user_id = sa.Column(sa.Integer(), primary_key = True) role = sa.Column(sa.Integer(), nullable = False) - creation_time = sa.Column(sa.DateTime(), nullable = True) - update_time = sa.Column(sa.DateTime(), nullable = True) + creation_time = sa.Column(mysql.TIMESTAMP, nullable = True) + update_time = sa.Column(mysql.TIMESTAMP, nullable = True) sa.ForeignKeyConstraint(['project_id'], [u'project.project_id'], ), sa.ForeignKeyConstraint(['role'], [u'role.role_id'], ), sa.ForeignKeyConstraint(['user_id'], [u'user.user_id'], ), @@ -79,8 +80,8 @@ class Project(Base): project_id = sa.Column(sa.Integer, primary_key=True) owner_id = sa.Column(sa.ForeignKey(u'user.user_id'), nullable=False, index=True) name = sa.Column(sa.String(30), nullable=False, unique=True) - creation_time = sa.Column(sa.DateTime) - update_time = sa.Column(sa.DateTime) + creation_time = sa.Column(mysql.TIMESTAMP) + update_time = sa.Column(mysql.TIMESTAMP) deleted = sa.Column(sa.Integer, nullable=False, server_default=sa.text("'0'")) public = sa.Column(sa.Integer, nullable=False, server_default=sa.text("'0'")) owner = relationship(u'User') diff --git a/migration/migration_harbor/versions/0_1_1.py b/migration/migration_harbor/versions/0_1_1.py index ecec2cfb30..f3ea874a51 100644 --- a/migration/migration_harbor/versions/0_1_1.py +++ b/migration/migration_harbor/versions/0_1_1.py @@ -27,9 +27,10 @@ branch_labels = None depends_on = None from alembic import op -from datetime import datetime from db_meta import * +from sqlalchemy.dialects import mysql + Session = sessionmaker() def upgrade(): @@ -44,12 +45,9 @@ def upgrade(): session.add(Properties(k='schema_version', v='0.1.1')) #add column to table user - op.add_column('user', sa.Column('creation_time', sa.DateTime(), nullable=True)) + op.add_column('user', sa.Column('creation_time', mysql.TIMESTAMP, nullable=True)) op.add_column('user', sa.Column('sysadmin_flag', sa.Integer(), nullable=True)) - op.add_column('user', sa.Column('update_time', sa.DateTime(), nullable=True)) - - #fill update_time data into table user - session.query(User).update({User.update_time: datetime.now()}) + op.add_column('user', sa.Column('update_time', mysql.TIMESTAMP, nullable=True)) #init all sysadmin_flag = 0 session.query(User).update({User.sysadmin_flag: 0}) @@ -62,7 +60,7 @@ def upgrade(): for result in join_result: session.add(ProjectMember(project_id=result.project_role.project_id, \ user_id=result.user_id, role=result.project_role.role_id, \ - creation_time=datetime.now(), update_time=datetime.now())) + creation_time=None, update_time=None)) #update sysadmin_flag sys_admin_result = session.query(UserProjectRole).\ @@ -88,11 +86,9 @@ def upgrade(): session.delete(acc) session.query(Access).update({Access.access_id: Access.access_id - 1}) - #add column to table project - op.add_column('project', sa.Column('update_time', sa.DateTime(), nullable=True)) + #add column to table project + op.add_column('project', sa.Column('update_time', mysql.TIMESTAMP, nullable=True)) - #fill update_time data into table project - session.query(Project).update({Project.update_time: datetime.now()}) session.commit() def downgrade(): diff --git a/static/i18n/locale_de-DE.ini b/static/i18n/locale_de-DE.ini index 79d08dded7..c5303e2f97 100644 --- a/static/i18n/locale_de-DE.ini +++ b/static/i18n/locale_de-DE.ini @@ -75,6 +75,7 @@ language_en-US = English language_zh-CN = 中文 language_de-DE = Deutsch language_ru-RU = Русский +language_ja-JP = 日本語 copyright = Copyright all_rights_reserved = Alle Rechte vorbehalten. index_desc = Project Harbor ist ein zuverlässiger Enterprise-Class Registry Server. Unternehmen können ihren eigenen Registry Server aufsetzen um die Produktivität und Sicherheit zu erhöhen. Project Harbor kann für Entwicklungs- wie auch Produktiv-Umgebungen genutzt werden. diff --git a/static/i18n/locale_en-US.ini b/static/i18n/locale_en-US.ini index 414e6c6472..7444d4537f 100644 --- a/static/i18n/locale_en-US.ini +++ b/static/i18n/locale_en-US.ini @@ -76,6 +76,7 @@ language_en-US = English language_zh-CN = 中文 language_de-DE = Deutsch language_ru-RU = Русский +language_ja-JP = 日本語 copyright = Copyright all_rights_reserved = All rights reserved. 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. diff --git a/static/i18n/locale_ja-JP.ini b/static/i18n/locale_ja-JP.ini new file mode 100644 index 0000000000..cf93bcbe12 --- /dev/null +++ b/static/i18n/locale_ja-JP.ini @@ -0,0 +1,89 @@ +page_title_index = Harbor +page_title_sign_in = ログイン - Harbor +page_title_project = プロジェクト - Harbor +page_title_item_details = 詳しい - Harbor +page_title_registration = 登録 - Harbor +page_title_add_user = ユーザを追加 - Harbor +page_title_forgot_password = パスワードを忘れました - Harbor +title_forgot_password = パスワードを忘れました +page_title_reset_password = パスワードをリセット - Harbor +title_reset_password = パスワードをリセット +page_title_change_password = パスワードを変更 - Harbor +title_change_password = パスワードを変更 +page_title_search = サーチ - Harbor +sign_in = ログイン +sign_up = 登録 +add_user = ユーザを追加 +log_out = ログアウト +search_placeholder = プロジェクト名またはイメージ名 +change_password = パスワードを変更 +username_email = ユーザ名/メールアドレス +password = パスワード +forgot_password = パスワードを忘れました +welcome = ようこそ +my_projects = マイプロジェクト +public_projects = パブリックプロジェクト +admin_options = 管理者 +project_name = プロジェクト名 +creation_time = 作成日時 +publicity = パブリック +add_project = プロジェクトを追加 +check_for_publicity = パブリックプロジェクト +button_save = 保存する +button_cancel = 取り消しする +button_submit = 送信する +username = ユーザ名 +email = メールアドレス +system_admin = システム管理者 +dlg_button_ok = OK +dlg_button_cancel = 取り消し +registration = 登録 +username_description = ログイン際に使うユーザ名を入力してください。 +email_description = メールアドレスはパスワードをリセットする際に使われます。 +full_name = フルネーム +full_name_description = フルネームを入力してください。 +password_description = パスワード7英数字以上で、少なくとも 1小文字、 1大文字と 1数字でなければなりません。 +confirm_password = パスワードを確認する +note_to_the_admin = メモ +old_password = 現在のパスワード +new_password = 新しいパスワード +forgot_password_description = ぱプロジェクトをリセットするメールはこのアドレスに送信します。 + +projects = プロジェクト +repositories = リポジトリ +search = サーチ +home = ホーム +project = プロジェクト +owner = オーナー +repo = リポジトリ +user = ユーザ +logs = ログ +repo_name = リポジトリ名 +repo_tag = リポジトリタグ +add_members = メンバーを追加 +operation = 操作 +advance = さらに絞りこみで検索 +all = 全部 +others = その他 +start_date = 開始日 +end_date = 終了日 +timestamp = タイムスタンプ +role = 役割 +reset_email_hint = このリンクをクリックしてパスワードリセットの処理を続けてください +reset_email_subject = パスワードをリセットします +language = 日本語 +language_en-US = English +language_zh-CN = 中文 +language_de-DE = Deutsch +language_ru-RU = Русский +language_ja-JP = 日本語 +copyright = コピーライト +all_rights_reserved = 無断複写・転載を禁じます +index_desc = Harborは、信頼性の高いエンタープライズクラスのRegistryサーバです。タープライズユーザはHarborを利用し、プライベートのRegistryサビースを構築し、生産性および安全性を向上させる事ができます。開発環境はもちろん、生産環境にも使用する事ができます。 +index_desc_0 = 主な利点: +index_desc_1 = 1. セキュリティ: 知的財産権を組織内で確保する。 +index_desc_2 = 2. 効率: プライベートなので、パブリックRegistryサビースにネットワーク通信が減らす。 +index_desc_3 = 3. アクセス制御: ロールベースアクセス制御機能を実装し、更に既存のユーザ管理システム(AD/LDAP)と統合することも可能。 +index_desc_4 = 4. 監査: すべてRegistryサビースへの操作が記録され、検査にに利用できる。 +index_desc_5 = 5. 管理UI: 使いやすい管理UIが搭載する。 +index_title = エンタープライズ Registry サビース diff --git a/static/i18n/locale_messages.js b/static/i18n/locale_messages.js index 6ba513b7b3..819dd53d0e 100644 --- a/static/i18n/locale_messages.js +++ b/static/i18n/locale_messages.js @@ -16,378 +16,441 @@ var global_messages = { "username_is_required" : { "en-US": "Username is required.", "zh-CN": "用户名为必填项。", + "ja-JP": "ユーザ名は必須項目です。", "de-DE": "Benutzername erforderlich.", "ru-RU": "Требуется ввести имя пользователя." }, "username_has_been_taken" : { "en-US": "Username has been taken.", "zh-CN": "用户名已被占用。", + "ja-JP": "ユーザ名はすでに登録されました。", "de-DE": "Benutzername bereits vergeben.", "ru-RU": "Имя пользователя уже используется." }, "username_is_too_long" : { "en-US": "Username is too long. (maximum 20 characters)", "zh-CN": "用户名长度超出限制。(最长为20个字符)", + "ja-JP": "ユーザ名が長すぎです。(20文字まで)", "de-DE": "Benutzername ist zu lang. (maximal 20 Zeichen)", "ru-RU": "Имя пользователя слишком длинное. (максимум 20 символов)" }, "username_contains_illegal_chars": { "en-US": "Username contains illegal character(s).", "zh-CN": "用户名包含不合法的字符。", + "ja-JP": "ユーザ名に使えない文字が入っています。", "de-DE": "Benutzername enthält ungültige Zeichen.", "ru-RU": "Имя пользователя содержит недопустимые символы." }, "email_is_required" : { "en-US": "Email is required.", "zh-CN": "邮箱为必填项。", + "ja-JP": "メールアドレスが必須です。", "de-DE": "E-Mail Adresse erforderlich.", "ru-RU": "Требуется ввести E-mail адрес." }, "email_contains_illegal_chars" : { "en-US": "Email contains illegal character(s).", "zh-CN": "邮箱包含不合法的字符。", + "ja-JP": "メールアドレスに使えない文字が入っています。", "de-DE": "E-Mail Adresse enthält ungültige Zeichen.", "ru-RU": "E-mail адрес содержит недопеустимые символы." }, "email_has_been_taken" : { "en-US": "Email has been taken.", "zh-CN": "邮箱已被占用。", + "ja-JP": "メールアドレスがすでに使われました。", "de-DE": "E-Mail Adresse wird bereits verwendet.", "ru-RU": "Такой E-mail адрес уже используется." }, "email_content_illegal" : { "en-US": "Email format is illegal.", "zh-CN": "邮箱格式不合法。", + "ja-JP": "メールアドレスフォーマットエラー。", "de-DE": "Format der E-Mail Adresse ist ungültig.", "ru-RU": "Недопустимый формат E-mail адреса." }, "email_does_not_exist" : { "en-US": "Email does not exist.", "zh-CN": "邮箱不存在。", + "ja-JP": "メールアドレスが存在しません。", "de-DE": "E-Mail Adresse existiert nicht.", "ru-RU": "E-mail адрес не существует." }, "realname_is_required" : { "en-US": "Full name is required.", "zh-CN": "全名为必填项。", + "ja-JP": "フルネームが必須です。", "de-DE": "Vollständiger Name erforderlich.", "ru-RU": "Требуется ввести полное имя." }, "realname_is_too_long" : { "en-US": "Full name is too long. (maximum 20 characters)", "zh-CN": "全名长度超出限制。(最长为20个字符)", + "ja-JP": "フルネームは長すぎです。(20文字まで)", "de-DE": "Vollständiger Name zu lang. (maximal 20 Zeichen)", "ru-RU": "Полное имя слишком длинное. (максимум 20 символов)" }, "realname_contains_illegal_chars" : { "en-US": "Full name contains illegal character(s).", "zh-CN": "全名包含不合法的字符。", + "ja-JP": "フルネームに使えない文字が入っています。", "de-DE": "Vollständiger Name enthält ungültige Zeichen.", "ru-RU": "Полное имя содержит недопустимые символы." }, "password_is_required" : { "en-US": "Password is required.", "zh-CN": "密码为必填项。", + "ja-JP": "パスワードは必須です。", "de-DE": "Passwort erforderlich.", "ru-RU": "Требуется ввести пароль." }, "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个数字。", + "ja-JP": "無効なパスワードです。7英数字以上で、 少なくとも1小文字、1大文字と1数字となります。", "de-DE": "Passwort ungültig. Mindestens sieben Zeichen bestehend aus einem Kleinbuchstaben, einem Großbuchstaben und einer Zahl", "ru-RU": "Такой пароль недопустим. Парольл должен содержать Минимум 7 символов, в которых будет присутствовать по меньшей мере 1 буква нижнего регистра, 1 буква верхнего регистра и 1 цифра" }, "password_is_too_long" : { "en-US": "Password is too long. (maximum 20 characters)", "zh-CN": "密码长度超出限制。(最长为20个字符)", + "ja-JP": "パスワードは長すぎです。(20文字まで)", "de-DE": "Passwort zu lang. (maximal 20 Zeichen)", "ru-RU": "Пароль слишком длинный (максимум 20 символов)" }, "password_does_not_match" : { "en-US": "Passwords do not match.", "zh-CN": "两次密码输入不一致。", + "ja-JP": "確認のパスワードが正しくありません。", "de-DE": "Passwörter stimmen nicht überein.", "ru-RU": "Пароли не совпадают." }, "comment_is_too_long" : { "en-US": "Comment is too long. (maximum 20 characters)", "zh-CN": "备注长度超出限制。(最长为20个字符)", + "ja-JP": "コメントは長すぎです。(20文字まで)", "de-DE": "Kommentar zu lang. (maximal 20 Zeichen)", "ru-RU": "Комментарий слишком длинный. (максимум 20 символов)" }, "comment_contains_illegal_chars" : { "en-US": "Comment contains illegal character(s).", "zh-CN": "备注包含不合法的字符。", + "ja-JP": "コメントに使えない文字が入っています。", "de-DE": "Kommentar enthält ungültige Zeichen.", "ru-RU": "Комментарий содержит недопустимые символы." }, "project_name_is_required" : { "en-US": "Project name is required.", "zh-CN": "项目名称为必填项。", + "ja-JP": "プロジェクト名は必須です。", "de-DE": "Projektname erforderlich.", "ru-RU": "Необходимо ввести название Проекта." }, "project_name_is_too_short" : { "en-US": "Project name is too short. (minimum 4 characters)", "zh-CN": "项目名称至少要求 4个字符。", + "ja-JP": "プロジェクト名は4文字以上です。", "de-DE": "Projektname zu kurz. (mindestens 4 Zeichen)", "ru-RU": "Название проекта слишком короткое. (миниму 4 символа)" }, "project_name_is_too_long" : { "en-US": "Project name is too long. (maximum 30 characters)", "zh-CN": "项目名称长度超出限制。(最长为30个字符)", + "ja-JP": "プロジェクト名は長すぎです。(30文字まで)", "de-DE": "Projektname zu lang. (maximal 30 Zeichen)", "ru-RU": "Название проекта слишком длинное (максимум 30 символов)" }, "project_name_contains_illegal_chars" : { "en-US": "Project name contains illegal character(s).", "zh-CN": "项目名称包含不合法的字符。", + "ja-JP": "プロジェクト名に使えない文字が入っています。", "de-DE": "Projektname enthält ungültige Zeichen.", "ru-RU": "Название проекта содержит недопустимые символы." }, "project_exists" : { "en-US": "Project exists.", "zh-CN": "项目已存在。", + "ja-JP": "プロジェクトはすでに存在しました。", "de-DE": "Projekt existiert bereits.", "ru-RU": "Такой проект уже существует." }, "delete_user" : { "en-US": "Delete User", "zh-CN": "删除用户", + "ja-JP": "ユーザを削除", "de-DE": "Benutzer löschen", "ru-RU": "Удалить пользователя" }, "are_you_sure_to_delete_user" : { "en-US": "Are you sure to delete ", "zh-CN": "确认要删除用户 ", + "ja-JP": "ユーザを削除でよろしでしょうか ", "de-DE": "Sind Sie sich sicher, dass Sie folgenden Benutzer löschen möchten: ", "ru-RU": "Вы уверены что хотите удалить пользователя? " }, "input_your_username_and_password" : { "en-US": "Please input your username and password.", "zh-CN": "请输入用户名和密码。", + "ja-JP": "ユーザ名とパスワードを入力してください。", "de-DE": "Bitte geben Sie ihr Benutzername und Passwort ein.", "ru-RU": "Введите имя пользователя и пароль." }, "check_your_username_or_password" : { "en-US": "Please check your username or password.", "zh-CN": "请输入正确的用户名或密码。", + "ja-JP": "正しいユーザ名とパスワードを入力してください。", "de-DE": "Bitte überprüfen Sie ihren Benutzernamen und Passwort.", "ru-RU": "Проверьте свои имя пользователя и пароль." }, "title_login_failed" : { "en-US": "Login Failed", "zh-CN": "登录失败", + "ja-JP": "ログインに失敗しました。", "de-DE": "Anmeldung fehlgeschlagen", "ru-RU": "Ошибка входа" }, "title_change_password" : { "en-US": "Change Password", "zh-CN": "修改密码", + "ja-JP": "パスワードを変更します。", "de-DE": "Passwort ändern", "ru-RU": "Сменить пароль" }, "change_password_successfully" : { "en-US": "Password changed successfully.", "zh-CN": "密码已修改。", + "ja-JP": "パスワードを変更しました。", "de-DE": "Passwort erfolgreich geändert.", "ru-RU": "Пароль успешно изменен." }, "title_forgot_password" : { "en-US": "Forgot Password", "zh-CN": "忘记密码", + "ja-JP": "パスワードをリセットします。", "de-DE": "Passwort vergessen", "ru-RU": "Забыли пароль?" }, "email_has_been_sent" : { "en-US": "Email for resetting password has been sent.", "zh-CN": "重置密码邮件已发送。", + "ja-JP": "パスワードをリセットするメールを送信しました。", "de-DE": "Eine E-Mail mit einem Wiederherstellungslink wurde an Sie gesendet.", "ru-RU": "На ваш E-mail было выслано письмо с инструкциями по сбросу пароля." }, "send_email_failed" : { "en-US": "Failed to send Email for resetting password.", "zh-CN": "重置密码邮件发送失败。", + "ja-JP": "パスワードをリセットするメールを送信する際エラーが出ました", "de-DE": "Fehler beim Senden der Wiederherstellungs-E-Mail.", "ru-RU": "Ошибка отправки сообщения." }, "please_login_first" : { "en-US": "Please login first.", "zh-CN": "请先登录。", + "ja-JP": "この先にログインが必要です。", "de-DE": "Bitte melden Sie sich zuerst an.", "ru-RU": "Сначала выполните вход в систему." }, "old_password_is_not_correct" : { "en-US": "Old password is not correct.", "zh-CN": "原密码输入不正确。", + "ja-JP": "現在のパスワードが正しく入力されていません。", "de-DE": "Altes Passwort ist nicht korrekt.", "ru-RU": "Старый пароль введен неверно." }, "please_input_new_password" : { "en-US": "Please input new password.", "zh-CN": "请输入新密码。", + "ja-JP": "あたらしいパスワードを入力してください", "de-DE": "Bitte geben Sie ihr neues Passwort ein.", "ru-RU": "Пожалуйста, введите новый пароль." }, "invalid_reset_url": { "en-US": "Invalid URL for resetting password.", "zh-CN": "无效密码重置链接。", + "ja-JP": "無効なパスワードをリセットするリンク。", "de-DE": "Ungültige URL zum Passwort wiederherstellen.", "ru-RU": "Неверный URL для сброса пароля." }, "reset_password_successfully" : { "en-US": "Reset password successfully.", "zh-CN": "密码重置成功。", + "ja-JP": "パスワードをリセットしました。", "de-DE": "Passwort erfolgreich wiederhergestellt.", "ru-RU": "Пароль успешно сброшен." }, "internal_error": { "en-US": "Internal error.", "zh-CN": "内部错误,请联系系统管理员。", + "ja-JP": "エラーが出ました、管理者に連絡してください。", "de-DE": "Interner Fehler.", "ru-RU": "Внутренняя ошибка." }, "title_reset_password" : { "en-US": "Reset Password", "zh-CN": "重置密码", + "ja-JP": "パスワードをリセットする", "de-DE": "Passwort zurücksetzen", "ru-RU": "Сбросить пароль" }, "title_sign_up" : { "en-US": "Sign Up", "zh-CN": "注册", + "ja-JP": "登録", "de-DE": "Registrieren", "ru-RU": "Регистрация" }, "title_add_user": { "en-US": "Add User", "zh-CN": "新增用户", + "ja-JP": "ユーザを追加", "de-DE": "Benutzer hinzufügen", "ru-RU": "Добавить пользователя" }, "registered_successfully": { "en-US": "Signed up successfully.", "zh-CN": "注册成功。", + "ja-JP": "登録しました。", "de-DE": "Erfolgreich registriert.", "ru-RU": "Регистрация прошла успешно." }, "registered_failed" : { "en-US": "Failed to sign up.", "zh-CN": "注册失败。", + "ja-JP": "登録でませんでした。", "de-DE": "Registrierung fehlgeschlagen.", "ru-RU": "Ошибка регистрации." }, "added_user_successfully": { "en-US": "Added user successfully.", "zh-CN": "新增用户成功。", + "ja-JP": "ユーザを追加しました。", "de-DE": "Benutzer erfolgreich erstellt.", "ru-RU": "Пользователь успешно добавлен." }, "added_user_failed": { "en-US": "Adding user failed.", "zh-CN": "新增用户失败。", + "ja-JP": "ユーザを追加できませんでした。", "de-DE": "Benutzer erstellen fehlgeschlagen.", "ru-RU": "Ошибка добавления пользователя." }, "projects": { "en-US": "Projects", "zh-CN": "项目", + "ja-JP": "プロジェクト", "de-DE": "Projekte", "ru-RU": "Проекты" }, "repositories" : { "en-US": "Repositories", "zh-CN": "镜像仓库", + "ja-JP": "リポジトリ", "de-DE": "Repositories", "ru-RU": "Репозитории" }, "no_repo_exists" : { "en-US": "No repositories found, please use 'docker push' to upload images.", "zh-CN": "未发现镜像,请用‘docker push’命令上传镜像。", + "ja-JP": "イメージが見つかりませんでした。’docker push’を利用しイメージをアップロードしてください。", "de-DE": "Keine Repositories gefunden, bitte benutzen Sie 'docker push' um ein Image hochzuladen.", "ru-RU": "Репозитории не найдены, используйте команду 'docker push' для добавления образов." }, "tag" : { "en-US": "Tag", "zh-CN": "标签", + "ja-JP": "タグ", "de-DE": "Tag", "ru-RU": "Метка" }, "pull_command": { "en-US": "Pull Command", "zh-CN": "Pull 命令", + "ja-JP": "Pull コマンド", "de-DE": "Pull Befehl", "ru-RU": "Команда для скачивания образа" }, "image_details" : { "en-US": "Image Details", "zh-CN": "镜像详细信息", + "ja-JP": "イメージ詳細", "de-DE": "Image Details", "ru-RU": "Информация об образе" }, "add_members" : { "en-US": "Add Member", "zh-CN": "添加成员", + "ja-JP": "メンバーを追加する", "de-DE": "Mitglied hinzufügen", "ru-RU": "Добавить Участника" }, "edit_members" : { "en-US": "Edit Members", "zh-CN": "编辑成员", + "ja-JP": "メンバーを編集する", "de-DE": "Mitglieder bearbeiten", "ru-RU": "Редактировать Участников" }, "add_member_failed" : { "en-US": "Adding Member Failed", "zh-CN": "添加成员失败", + "ja-JP": "メンバーを追加できません出した", "de-DE": "Mitglied hinzufügen fehlgeschlagen", "ru-RU": "Ошибка при добавлении нового участника" }, "please_input_username" : { "en-US": "Please input a username.", "zh-CN": "请输入用户名。", + "ja-JP": "ユーザ名を入力してください。", "de-DE": "Bitte geben Sie einen Benutzernamen ein.", "ru-RU": "Пожалуйста, введите имя пользователя." }, "please_assign_a_role_to_user" : { "en-US": "Please assign a role to the user.", "zh-CN": "请为用户分配角色。", + "ja-JP": "ユーザーに役割を割り当てるしてください。", "de-DE": "Bitte weisen Sie dem Benutzer eine Rolle zu.", "ru-RU": "Пожалуйста, назначьте роль пользователю." }, "user_id_exists" : { "en-US": "User is already a member.", "zh-CN": "用户已经是成员。", + "ja-JP": "すでにメンバーに登録しました。", "de-DE": "Benutzer ist bereits Mitglied.", "ru-RU": "Пользователь уже является участником." }, "user_id_does_not_exist" : { "en-US": "User does not exist.", "zh-CN": "不存在此用户。", + "ja-JP": "ユーザが見つかりませんでした。", "de-DE": "Benutzer existiert nicht.", "ru-RU": "Пользователя с таким именем не существует." }, "insufficient_privileges" : { "en-US": "Insufficient privileges.", "zh-CN": "权限不足。", + "ja-JP": "権限エラー。", "de-DE": "Unzureichende Berechtigungen.", "ru-RU": "Недостаточно прав." }, "operation_failed" : { "en-US": "Operation Failed", "zh-CN": "操作失败", + "ja-JP": "操作に失敗しました。", "de-DE": "Befehl fehlgeschlagen", "ru-RU": "Ошибка при выполнении данной операции" }, "button_on" : { "en-US": "On", "zh-CN": "打开", + "ja-JP": "オン", "de-DE": "An", "ru-RU": "Вкл." }, "button_off" : { "en-US": "Off", "zh-CN": "关闭", + "ja-JP": "オフ", "de-DE": "Aus", "ru-RU": "Откл." } diff --git a/static/i18n/locale_ru-RU.ini b/static/i18n/locale_ru-RU.ini index 731584abb8..eb5521e0b9 100644 --- a/static/i18n/locale_ru-RU.ini +++ b/static/i18n/locale_ru-RU.ini @@ -76,6 +76,7 @@ language_en-US = English language_zh-CN = 中文 language_de-DE = Deutsch language_ru-RU = Русский +language_ja-JP = 日本語 copyright = Copyright all_rights_reserved = Все права защищены. index_desc = Проект Harbor представляет собой надежный сервер управления docker-образами корпоративного класса. Компании могут использовать данный сервер в своей инфарструктуе для повышения производительности и безопасности . Проект Harbor может использоваться как в среде разработки так и в продуктивной среде. diff --git a/static/i18n/locale_zh-CN.ini b/static/i18n/locale_zh-CN.ini index 69c34886b3..f5940a9af7 100644 --- a/static/i18n/locale_zh-CN.ini +++ b/static/i18n/locale_zh-CN.ini @@ -76,6 +76,7 @@ language_en-US = English language_zh-CN = 中文 language_de-DE = Deutsch language_ru-RU = Русский +language_ja-JP = 日本語 copyright = 版权所有 all_rights_reserved = 保留所有权利。 index_desc = Harbor是可靠的企业级Registry服务器。企业用户可使用Harbor搭建私有容器Registry服务,提高生产效率和安全度,既可应用于生产环境,也可以在开发环境中使用。 diff --git a/static/resources/js/common.js b/static/resources/js/common.js index 7c7397d6b3..78cdfc638e 100644 --- a/static/resources/js/common.js +++ b/static/resources/js/common.js @@ -70,7 +70,8 @@ var SUPPORT_LANGUAGES = { "en-US": "English", "zh-CN": "Chinese", "de-DE": "German", - "ru-RU": "Russian" + "ru-RU": "Russian", + "ja-JP": "Japanese" }; var DEFAULT_LANGUAGE = "en-US"; diff --git a/static/resources/js/item-detail.js b/static/resources/js/item-detail.js index 6f445f7178..c63b1a69b2 100644 --- a/static/resources/js/item-detail.js +++ b/static/resources/js/item-detail.js @@ -62,7 +62,7 @@ jQuery(function(){ return; } $.each(data, function(i, e){ - var targetId = e.replace(/\//g, "------"); + var targetId = e.replace(/\//g, "------").replace(/\./g, "---"); var row = '
' + '