mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 10:45:45 +01:00
merged from upstream/master
This commit is contained in:
commit
34e4c4e6f7
1
AUTHORS
1
AUTHORS
@ -5,6 +5,7 @@ Alexey Erkak <eryigin at mail.ru>
|
||||
Allen Heavey <xheavey at gmail.com>
|
||||
Amanda Zhang <amzhang at vmware.com>
|
||||
Benniu Ji <benniuji at gmail.com>
|
||||
Bin Liu <liubin0329 at gmail.com>
|
||||
Bobby Zhang <junzhang at vmware.com>
|
||||
Chaofeng Wu <chaofengw at vmware.com>
|
||||
Daniel Jiang <jiangd at vmware.com>
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
<a href="https://www.caicloud.io" border="0"><img alt="CaiCloud" src="docs/img/caicloudLogoWeb.png"></a>
|
||||
|
||||
### Users
|
||||
<a href="https://www.madailicai.com/" border="0" target="_blank"><img alt="MaDaiLiCai" src="docs/img/UserMaDai.jpg"></a>
|
||||
<a href="https://www.madailicai.com/" border="0" target="_blank"><img alt="MaDaiLiCai" src="docs/img/UserMaDai.jpg"></a> <a href="https://www.dianrong.com/" border="0" target="_blank"><img alt="Dianrong" src="docs/img/dianrong.png"></a>
|
||||
|
||||
### Supporting Technologies
|
||||
<img alt="beego" src="docs/img/beegoLogo.png"> Harbor is powered by <a href="http://beego.me/">Beego</a>, an open source framework to build and develop applications in the Go way.
|
||||
|
47
ROADMAP.md
Normal file
47
ROADMAP.md
Normal file
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
|
BIN
docs/img/dianrong.png
Normal file
BIN
docs/img/dianrong.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
@ -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
|
||||
```
|
||||
|
@ -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')
|
||||
|
@ -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).\
|
||||
@ -89,10 +87,8 @@ def upgrade():
|
||||
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))
|
||||
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():
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
89
static/i18n/locale_ja-JP.ini
Normal file
89
static/i18n/locale_ja-JP.ini
Normal file
@ -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 サビース
|
@ -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": "Откл."
|
||||
}
|
||||
|
@ -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 может использоваться как в среде разработки так и в продуктивной среде.
|
||||
|
@ -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服务,提高生产效率和安全度,既可应用于生产环境,也可以在开发环境中使用。
|
||||
|
@ -71,7 +71,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";
|
||||
|
@ -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 = '<div class="panel panel-default" targetId="' + targetId + '">' +
|
||||
'<div class="panel-heading" role="tab" id="heading' + i + '"+ >' +
|
||||
'<h4 class="panel-title">' +
|
||||
@ -97,7 +97,6 @@ jQuery(function(){
|
||||
}
|
||||
}
|
||||
}).exec();
|
||||
}
|
||||
$("#btnSearchRepo").on("click", function(){
|
||||
listRepo($.trim($("#txtRepoName").val()));
|
||||
});
|
||||
@ -132,6 +131,41 @@ jQuery(function(){
|
||||
}
|
||||
data.Created = moment(new Date(data.Created)).format("YYYY-MM-DD HH:mm:ss");
|
||||
$("#dlgModal").dialogModal({"title": i18n.getMessage("image_details"), "content": data});
|
||||
=======
|
||||
}
|
||||
}).exec();
|
||||
}
|
||||
$("#btnSearchRepo").on("click", function(){
|
||||
listRepo($.trim($("#txtRepoName").val()));
|
||||
});
|
||||
|
||||
$('#accordionRepo').on('show.bs.collapse', function (e) {
|
||||
$('#accordionRepo .in').collapse('hide');
|
||||
var targetId = $(e.target).attr("targetId");
|
||||
var repoName = targetId.replace(/[-]{6}/g, "/").replace(/[-]{3}/g, '.');
|
||||
new AjaxUtil({
|
||||
url: "/api/repositories/tags?repo_name=" + repoName,
|
||||
type: "get",
|
||||
success: function(data, status, xhr){
|
||||
$('#' + targetId +' table tbody tr').remove();
|
||||
var row = [];
|
||||
for(var i in data){
|
||||
var tagName = data[i];
|
||||
row.push('<tr><td><a href="#" imageId="' + tagName + '" repoName="' + repoName + '">' + tagName + '</a></td><td><input type="text" style="width:100%" readonly value=" docker pull '+ $("#harborRegUrl").val() +'/'+ repoName + ':' + tagName +'"></td></tr>');
|
||||
}
|
||||
$('#' + targetId +' table tbody').append(row.join(""));
|
||||
$('#' + targetId +' table tbody tr a').on("click", function(e){
|
||||
var imageId = $(this).attr("imageId");
|
||||
var repoName = $(this).attr("repoName");
|
||||
new AjaxUtil({
|
||||
url: "/api/repositories/manifests?repo_name=" + repoName + "&tag=" + imageId,
|
||||
type: "get",
|
||||
success: function(data, status, xhr){
|
||||
if(data){
|
||||
for(var i in data){
|
||||
if(data[i] == ""){
|
||||
data[i] = "N/A";
|
||||
>>>>>>> upstream/master
|
||||
}
|
||||
}
|
||||
}).exec();
|
||||
|
@ -28,6 +28,7 @@
|
||||
<form class="navbar-form navbar-right">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
@ -39,6 +40,7 @@
|
||||
<li><a href="/language?lang=zh-CN">{{i18n .Lang "language_zh-CN"}}</a></li>
|
||||
<li><a href="/language?lang=de-DE">{{i18n .Lang "language_de-DE"}}</a></li>
|
||||
<li><a href="/language?lang=ru-RU">{{i18n .Lang "language_ru-RU"}}</a></li>
|
||||
<li><a href="/language?lang=ja-JP">{{i18n .Lang "language_ja-JP"}}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
Loading…
Reference in New Issue
Block a user