You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@submarine.apache.org by cd...@apache.org on 2022/11/30 03:58:08 UTC

[submarine] branch master updated: SUBMARINE-1152. Submarine UI support i18n

This is an automated email from the ASF dual-hosted git repository.

cdmikechen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/submarine.git


The following commit(s) were added to refs/heads/master by this push:
     new 21bd2687 SUBMARINE-1152. Submarine UI support i18n
21bd2687 is described below

commit 21bd2687b02c4ed78ce5868d13cce13e839af2c6
Author: cdmikechen <cd...@apache.org>
AuthorDate: Mon Nov 21 08:29:25 2022 +0800

    SUBMARINE-1152. Submarine UI support i18n
    
    ### What is this PR for?
    UI support translation by [ngx-translate/core](https://github.com/ngx-translate/core)
    
    ### What type of PR is it?
    Feature
    
    ### Todos
    * [x] - Add ngx-translate/core lib
    * [x] - Translate `Experiment` page
    
    ### What is the Jira issue?
    https://issues.apache.org/jira/projects/SUBMARINE/issues/SUBMARINE-1152
    
    ### How should this be tested?
    See Screenshot
    
    ### Screenshots (if appropriate)
    https://user-images.githubusercontent.com/12069428/201573071-bcf2d4f5-7e79-4fef-a9ad-7dd695697f13.mov
    
    ### Questions:
    * Do the license files need updating? No
    * Are there breaking changes for older versions? Yes
    * Does this need new documentation? No
    
    Author: cdmikechen <cd...@apache.org>
    
    Signed-off-by: cdmikechen <cd...@apache.org>
    
    Closes #1015 from cdmikechen/SUBMARINE-1152 and squashes the following commits:
    
    0defabfd [cdmikechen] Commit for python check fix
    b31ff43e [cdmikechen] add some model info
    aaac3fc0 [cdmikechen] add menu and experiment info
    17805242 [cdmikechen] Add some experiment translation
    4c836e9d [cdmikechen] Init translate service
---
 submarine-workbench/workbench-web/package.json     |  4 +-
 .../workbench-web/src/app/core/local-translate.ts  | 41 +++++++++++
 .../experiment-customized-form.component.html      | 28 ++++----
 .../experiment-form/experiment-form.component.html | 12 ++--
 .../experiment-predefined-form.component.html      | 22 +++---
 .../experiment-home/experiment-home.component.html | 20 +++---
 .../experiment-list/experiment-list.component.html | 34 ++++-----
 .../artifacts/artifacts.component.html             |  6 +-
 .../register-model-form.component.html             | 12 ++--
 .../register-model-tags.component.html             |  4 +-
 .../experiment-info/experiment-info.component.html | 40 +++++------
 .../hyper-params/hyper-params.component.html       |  3 +-
 .../experiment-info/metrics/metrics.component.html |  7 +-
 .../workbench/experiment/experiment.component.html |  6 +-
 .../workbench/experiment/experiment.module.ts      | 30 ++++----
 .../app/pages/workbench/workbench.component.html   | 38 +++++++---
 .../app/pages/workbench/workbench.component.scss   |  5 ++
 .../src/app/pages/workbench/workbench.component.ts | 33 ++++++---
 .../src/app/pages/workbench/workbench.module.ts    |  3 +
 .../workbench-web/src/assets/i18n/en.json          | 83 ++++++++++++++++++++++
 .../workbench-web/src/assets/i18n/zh-cn.json       | 83 ++++++++++++++++++++++
 21 files changed, 385 insertions(+), 129 deletions(-)

diff --git a/submarine-workbench/workbench-web/package.json b/submarine-workbench/workbench-web/package.json
index 3239d3e5..abc28a94 100644
--- a/submarine-workbench/workbench-web/package.json
+++ b/submarine-workbench/workbench-web/package.json
@@ -32,7 +32,9 @@
     "rxjs": "~6.4.0",
     "tslib": "^1.10.0",
     "yaml": "^1.10.2",
-    "zone.js": "~0.9.1"
+    "zone.js": "~0.9.1",
+    "@ngx-translate/core": "~12.1.2",
+    "@ngx-translate/http-loader": "^4.0.0"
   },
   "lint-staged": {
     "src/**/*.{js,json,ts,html}": [
diff --git a/submarine-workbench/workbench-web/src/app/core/local-translate.ts b/submarine-workbench/workbench-web/src/app/core/local-translate.ts
new file mode 100644
index 00000000..b4d81e43
--- /dev/null
+++ b/submarine-workbench/workbench-web/src/app/core/local-translate.ts
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { HttpClient } from '@angular/common/http';
+import { TranslateLoader } from '@ngx-translate/core';
+import { TranslateHttpLoader } from '@ngx-translate/http-loader';
+
+export function httpLoaderFactory(http: HttpClient) {
+  return new TranslateHttpLoader(http);
+}
+
+function getDefaultLang() {
+  const lang = localStorage.getItem('translate');
+  return lang === null || lang.length === 0 ? 'en' : lang;
+}
+
+const TRANSLATE_CONFIG = {
+  defaultLanguage: getDefaultLang(),
+  loader: {
+    provide: TranslateLoader,
+    useFactory: httpLoaderFactory,
+    deps: [HttpClient]
+  }
+}
+export default TRANSLATE_CONFIG;
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-customized-form/experiment-customized-form.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-customized-form/experiment-customized-form.component.html
index 649274c3..946be87f 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-customized-form/experiment-customized-form.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-customized-form/experiment-customized-form.component.html
@@ -19,9 +19,9 @@
 
 <div>
   <nz-steps [nzCurrent]="step">
-    <nz-step nzTitle="First Step"></nz-step>
-    <nz-step nzTitle="Second Step"></nz-step>
-    <nz-step nzTitle="Preview"></nz-step>
+    <nz-step nzTitle="{{'First Step' | translate}}"></nz-step>
+    <nz-step nzTitle="{{'Second Step' | translate}}"></nz-step>
+    <nz-step nzTitle="{{'Preview' | translate}}"></nz-step>
   </nz-steps>
 </div>
 <div>
@@ -31,7 +31,7 @@
         <div class="single-field-group">
           <label for="experimentName">
             <span class="red-star">*</span>
-            Experiment Name
+            {{'Experiment Name' | translate}}
           </label>
           <input
             nz-input
@@ -43,24 +43,24 @@
           />
           <div class="alert-message-container">
             <div class="alert-message" *ngIf="experiment.get('experimentName').hasError('pattern')">
-              Only letters(a-z), numbers(0-9), and hyphens are allowed, but you can't start or end with hyphens.
+              {{'Only letters(a - z), numbers(0 - 9), and hyphens are allowed, but you can`t start or end with hyphens.' | translate}}
             </div>
           </div>
         </div>
         <div class="single-field-group">
-          <label for="description">Description</label>
+          <label for="description">{{'Description' | translate}}</label>
           <textarea
             nz-input
             [nzAutosize]="{ minRows: 1, maxRows: 4 }"
             name="description"
             formControlName="description"
             id="description"
-            placeholder="Run distributed mnist example"
+            placeholder="{{'Run distributed mnist example' | translate}}"
           ></textarea>
         </div>
         <div class="single-field-group">
           <label for="tags">
-            Tags
+            {{'Tags' | translate}}
           </label>
           <nz-select
             formControlName="tags"
@@ -75,7 +75,7 @@
         <div class="single-field-group">
           <label for="cmd">
             <span class="red-star">*</span>
-            Command
+            {{'Command' | translate}}
           </label>
           <textarea
             nz-input
@@ -89,7 +89,7 @@
         <div class="single-field-group">
           <label for="image">
             <span class="red-star">*</span>
-            Image
+            {{'Image'| translate}}
           </label>
           <nz-select nzShowSearch [nzDropdownRender]="renderTemplate" name="image" formControlName="image" id="image">
             <nz-option *ngFor="let image of imageList" [nzValue]="image" [nzLabel]="image"></nz-option>
@@ -100,7 +100,7 @@
               <input type="text" nz-input #inputElement />
               <a class="add-item" (click)="addItem(inputElement)">
                 <i nz-icon nzType="plus"></i>
-                Add item
+                {{'Add item' | translate}}
               </a>
             </div>
           </ng-template>
@@ -113,7 +113,7 @@
             nzType="default"
             (click)="ADVANCED = !ADVANCED"
           >
-            Advanced
+            {{'Advanced' | translate}}
             <i nz-icon [nzType]="ADVANCED ? 'up' : 'down'"></i>
           </button>
         </div>
@@ -130,7 +130,7 @@
             />
           </nz-input-group>
           <ng-template #suffixTemplateInfo>
-            <i nz-icon nz-tooltip nzTitle="Copy git repo to /code/current in container." nzType="info-circle"></i>
+            <i nz-icon nz-tooltip nzTitle="{{'Copy git repo to /code/current in container.' | translate}}" nzType="info-circle"></i>
           </ng-template>
         </div>
         <div *ngIf="ADVANCED">
@@ -162,7 +162,7 @@
             </ng-container>
           </ul>
           <button nz-button id="env-btn" style="display: block; margin: auto" nzType="primary" (click)="onCreateEnv()">
-            Add new environment variable
+            {{'Add new environment variable' | translate}}
           </button>
           <br />
         </div>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-form.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-form.component.html
index 132e253a..1d34d8fb 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-form.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-form.component.html
@@ -19,7 +19,7 @@
 
 <nz-modal
   [(nzVisible)]="modalProps.isVisible"
-  nzTitle="Create Experiment"
+  nzTitle="{{'Create Experiment' | translate}}"
   (nzOnCancel)="closeModal()"
   [nzWidth]="1000"
   [nzContent]="modalContent"
@@ -28,10 +28,10 @@
   <ng-template #modalContent>
     <nz-button-group id="form-type-container" *ngIf="!modalProps.formType">
       <button nz-button nzType="primary" id="customized" (click)="modalProps.formType = 'customized'">
-        Define your experiment
+        {{'Define your experiment' | translate}}
       </button>
       <button nz-button nzType="primary" id="pre" (click)="modalProps.formType = 'predefined'">
-        From predefined experiment library
+        {{'From predefined experiment library' | translate}}
       </button>
     </nz-button-group>
     <submarine-experiment-customized-form
@@ -45,7 +45,7 @@
     ></submarine-experiment-predefined-form>
   </ng-template>
   <ng-template #modalFooter>
-    <button nz-button nzType="default" (click)="closeModal()">Cancel</button>
+    <button nz-button nzType="default" (click)="closeModal()">{{'Cancel' | translate}}</button>
     <button
       id="go"
       nz-button
@@ -54,10 +54,10 @@
       [disabled]="nextBtnDisable"
       (click)="proceedForm()"
     >
-      {{ modalProps.okText }}
+      {{ modalProps.okText | translate }}
     </button>
     <button *ngIf="modalProps.currentStep > 0" nz-button nzType="default" style="float: left" (click)="prevForm()">
-      Prev Step
+      {{'Prev Step' | translate}}
     </button>
   </ng-template>
 </nz-modal>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-predefined-form/experiment-predefined-form.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-predefined-form/experiment-predefined-form.component.html
index 5b9fe0ec..b947d5a0 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-predefined-form/experiment-predefined-form.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-form/experiment-predefined-form/experiment-predefined-form.component.html
@@ -19,11 +19,11 @@
 
 <form nz-form [formGroup]="predefinedForm">
   <nz-form-item>
-    <nz-form-label [nzSpan]="5" nzFor="predefined-template" nzRequired>predefined-template</nz-form-label>
-    <nz-form-control [nzSpan]="12" nzErrorTip="Please select templates.">
+    <nz-form-label [nzSpan]="5" nzFor="predefined-template" nzRequired>{{'predefined-template' | translate}}</nz-form-label>
+    <nz-form-control [nzSpan]="12" nzErrorTip="{{'Please select templates.' | translate}}">
       <nz-select
         id="predefined-template"
-        nzPlaceHolder="Select a predefined experiment template"
+        nzPlaceHolder="{{'Select a predefined experiment template' | translate}}"
         formControlName="templateName"
         (ngModelChange)="onTemplateChange()"
       >
@@ -33,7 +33,7 @@
   </nz-form-item>
 
   <div formGroupName="params" *ngIf="currentOption != null">
-    <h4 nz-typography>Configurable Parameters</h4>
+    <h4 nz-typography>{{'Configurable Parameters' | translate}}</h4>
     <nz-form-item *ngFor="let item of paramList">
       <nz-form-label [nzSpan]="5" [nzRequired]="item.required" [nzFor]="item.name">{{ item.name }}</nz-form-label>
       <nz-form-control [nzSpan]="12" nzErrorTip="Please provide the value!" *ngIf="item.name != 'experiment_name'">
@@ -42,7 +42,7 @@
       <nz-form-control [nzSpan]="12" *ngIf="item.name == 'experiment_name'">
         <input type="text" nz-input [id]="item.name" [formControlName]="item.name" />
         <div class="alert-message" *ngIf="predefinedForm.get('params').get(item.name).hasError('pattern')">
-          Only letters(a-z), numbers(0-9), and hyphens are allowed, but you can't start or end with hyphens.
+          {{'Only letters(a - z), numbers(0 - 9), and hyphens are allowed, but you can`t start or end with hyphens.' | translate}}
         </div>
       </nz-form-control>
     </nz-form-item>
@@ -50,22 +50,22 @@
 
   <nz-form-item *ngIf="currentOption != null">
     <nz-descriptions nzTitle="Spec" nzBordered [nzColumn]="{ xxl: 2, xl: 2, lg: 2, md: 2, sm: 2, xs: 1 }">
-      <nz-descriptions-item nzTitle="Name">
+      <nz-descriptions-item nzTitle="{{'Name' | translate}}">
         {{ templates[currentOption].experimentName }}
       </nz-descriptions-item>
-      <nz-descriptions-item nzTitle="Namespace">
+      <nz-descriptions-item nzTitle="{{'Namespace' | translate}}">
         {{ templates[currentOption].experimentNamespace }}
       </nz-descriptions-item>
-      <nz-descriptions-item nzTitle="Command" [nzSpan]="2">
+      <nz-descriptions-item nzTitle="{{'Command' | translate}}" [nzSpan]="2">
         {{ templates[currentOption].experimentCommand }}
       </nz-descriptions-item>
-      <nz-descriptions-item nzTitle="Image" [nzSpan]="2">
+      <nz-descriptions-item nzTitle="{{'Image' | translate}}" [nzSpan]="2">
         {{ templates[currentOption].experimentImage }}
       </nz-descriptions-item>
-      <nz-descriptions-item nzTitle="Environment Variables" [nzSpan]="2">
+      <nz-descriptions-item nzTitle="{{'Environment Variables' | translate}}" [nzSpan]="2">
         {{ templates[currentOption].experimentVars }}
       </nz-descriptions-item>
-      <nz-descriptions-item nzTitle="Tags">
+      <nz-descriptions-item nzTitle="{{'Tags' | translate}}">
         <nz-tag *ngFor="let tag of templates[currentOption].experimentTags">{{tag}}</nz-tag>
       </nz-descriptions-item>
     </nz-descriptions>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-home.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-home.component.html
index 9edbce64..d4fff700 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-home.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-home.component.html
@@ -20,14 +20,14 @@
 <div style="margin: 15px; padding: 15px; background-color: white">
   <div align="right">
     <div style="margin: 0px 4px 0px 4px; display: inline-block">
-      Auto Reload
+      {{ 'Auto Reload' | translate }}
       <nz-switch [(ngModel)]="switchValue" (click)="onSwitchAutoReload()"></nz-switch>
     </div>
 
     <nz-radio-group>
-      <label nz-radio-button nzValue="All">All</label>
-      <label nz-radio-button nzValue="Own">Owned By Me</label>
-      <label nz-radio-button nzValue="Access">Accessible By Me</label>
+      <label nz-radio-button nzValue="All">{{ 'All' | translate }}</label>
+      <label nz-radio-button nzValue="Own">{{ 'Owned By Me' | translate }}</label>
+      <label nz-radio-button nzValue="Access">{{ 'Accessible By Me' | translate }}</label>
     </nz-radio-group>
     <a
       nz-button
@@ -53,7 +53,7 @@
     </a>
     <br />
     <nz-input-group nzSearch style="width: 300px; margin: 10px 4px 10px 4px" [nzAddOnAfter]="suffixIconButton">
-      <input type="text" nz-input placeholder="input search text" />
+      <input type="text" nz-input placeholder="{{'input search text' | translate}}" />
     </nz-input-group>
     <ng-template #suffixIconButton>
       <button nz-button nzType="primary" nzSearch><i nz-icon nzType="search"></i></button>
@@ -67,7 +67,7 @@
       (click)="form.initModal('create')"
     >
       <i nz-icon nzType="plus"></i>
-      New Experiment
+      {{'New Experiment' | translate}}
     </button>
 
     <button
@@ -75,13 +75,13 @@
       nzType="primary"
       style="margin: 10px 4px 10px 4px"
       nz-popconfirm
-      nzTitle="Confirm to delete?"
-      nzCancelText="Cancel"
-      nzOkText="Ok"
+      nzTitle="{{'Confirm to delete?' | translate}}"
+      nzCancelText="{{'Cancel' | translate}}"
+      nzOkText="{{'Ok' | translate}}"
       (nzOnConfirm)="deleteExperiments()"
     >
       <i nz-icon nzType="delete"></i>
-      Delete
+      {{'Delete' | translate}}
     </button>
   </div>
   <submarine-experiment-list
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-list/experiment-list.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-list/experiment-list.component.html
index 36c88167..f8c77848 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-list/experiment-list.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-home/experiment-list/experiment-list.component.html
@@ -22,7 +22,7 @@
   nzBordered
   #basicTable
   [nzData]="experimentList"
-  [nzNoResult]="'No data'"
+  [nzNoResult]="'No data' | translate"
   [nzLoading]="isLoading"
 >
   <thead>
@@ -30,15 +30,15 @@
       <th>
         <label nz-checkbox [ngModel]="selectAllChecked" (ngModelChange)="onSelectAllClick($event)"></label>
       </th>
-      <th>Experiment Name</th>
-      <th>Experiment ID</th>
-      <th>Tags</th>
-      <th>Status</th>
-      <th>Finished Time</th>
-      <th>Created Time</th>
-      <th>Running Time</th>
-      <th>Duration</th>
-      <th>Action</th>
+      <th>{{ 'Experiment Name' | translate }}</th>
+      <th>{{ 'Experiment ID' | translate }}</th>
+      <th>{{ 'Tags' | translate }}</th>
+      <th>{{ 'Status' | translate }}</th>
+      <th>{{ 'Finished Time' | translate }}</th>
+      <th>{{ 'Created Time' | translate }}</th>
+      <th>{{ 'Running Time' | translate }}</th>
+      <th>{{ 'Duration' | translate }}</th>
+      <th>{{ 'Action' | translate }}</th>
     </tr>
   </thead>
   <tbody>
@@ -56,7 +56,7 @@
         <nz-tag *ngFor="let tag of data.spec.meta.tags">{{tag}}</nz-tag>
       </td>
       <td>
-        <nz-tag [nzColor]="statusColor[data.status]">{{ data.status }}</nz-tag>
+        <nz-tag [nzColor]="statusColor[data.status]">{{ data.status | translate}}</nz-tag>
       </td>
       <td>{{ data.finishedTime | date: 'M/d/yyyy, h:mm a' }}</td>
       <td>{{ data.createdTime | date: 'M/d/yyyy, h:mm a' }}</td>
@@ -64,7 +64,7 @@
       <td>{{ data.duration }}</td>
       <td class="td-action">
         <a (click)="initModal.emit({ initMode: 'clone', initFormType: 'customized', id: null, spec: data.spec })">
-          Clone
+          {{ 'Clone' | translate }}
         </a>
         <nz-divider nzType="vertical"></nz-divider>
         <a
@@ -72,18 +72,18 @@
             initModal.emit({ initMode: 'update', initFormType: 'customized', id: data.experimentId, spec: data.spec })
           "
         >
-          Update
+          {{ 'Update' | translate }}
         </a>
         <nz-divider nzType="vertical"></nz-divider>
         <a
           nz-popconfirm
           nzPlacement="left"
-          nzTitle="Are you sure you want to delete?"
-          nzCancelText="Cancel"
-          nzOkText="Ok"
+          nzTitle="{{ 'Are you sure you want to delete?' | translate }}"
+          nzCancelText="{{ 'Cancel' | translate }}"
+          nzOkText="{{ 'Ok' | translate }}"
           (nzOnConfirm)="onDeleteExperiment(data.experimentId)"
         >
-          Delete
+          {{ 'Delete' | translate }}
         </a>
       </td>
     </tr>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/artifacts.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/artifacts.component.html
index bc4f0b93..f25e992e 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/artifacts.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/artifacts.component.html
@@ -18,11 +18,11 @@
   -->
 
 <div id="artifactTable">
-  <nz-table #artifactTable nzSize="middle" [nzBordered]="true" [nzData]="artifactPaths" [nzNoResult]="'No data'">
+  <nz-table #artifactTable nzSize="middle" [nzBordered]="true" [nzData]="artifactPaths" [nzNoResult]="'No data' | translate">
     <thead>
       <tr>
         <th>ArtifactPath</th>
-        <th>Action</th>
+        <th>{{'Action' | translate}}</th>
       </tr>
     </thead>
     <tbody>
@@ -36,7 +36,7 @@
             style="margin: 10px 4px 10px 4px"
             (click)="form.initModal()"
           >
-            Register model
+            {{'Register model' | translate}}
           </button>
         </td>
         <register-model-form #form [baseDir]="artifactPath" [experimentId]="experimentID"></register-model-form>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/register-model-form/register-model-form.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/register-model-form/register-model-form.component.html
index 7a7b6c9f..d5a6721c 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/register-model-form/register-model-form.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/register-model-form/register-model-form.component.html
@@ -20,7 +20,7 @@
 <nz-modal [(nzVisible)]="isVisible" (nzOnCancel)="isVisible = false" nzTitle="Register Model" [nzWidth]="700">
   <form nz-form [formGroup]="registerModelForm" nzLayout="horizontal">
     <nz-form-item>
-      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>Model Name</nz-form-label>
+      <nz-form-label [nzSm]="6" [nzXs]="24" nzRequired>{{'Model Name' | translate}}</nz-form-label>
       <nz-form-control [nzSm]="14" [nzXs]="24">
         <nz-select nzShowSearch name="select-registered-model" formControlName="registeredModelName">
           <nz-option
@@ -34,14 +34,14 @@
     </nz-form-item>
 
     <nz-form-item>
-      <nz-form-label [nzSm]="6" [nzXs]="24">Tags</nz-form-label>
+      <nz-form-label [nzSm]="6" [nzXs]="24">{{'Tags' | translate}}</nz-form-label>
       <nz-form-control [nzSm]="14">
         <register-model-tags [tags]="tags.value"></register-model-tags>
       </nz-form-control>
     </nz-form-item>
 
     <nz-form-item>
-      <nz-form-label [nzSm]="6" [nzXs]="24">Description</nz-form-label>
+      <nz-form-label [nzSm]="6" [nzXs]="24">{{'Description' | translate}}</nz-form-label>
       <nz-form-control [nzSm]="14" [nzXs]="24" nzErrorTip="Please write something here!">
         <textarea
           nz-input
@@ -53,10 +53,10 @@
       </nz-form-control>
     </nz-form-item>
     <div *nzModalFooter>
-      <button id="btn-cancel" nz-button nzType="default" (click)="closeModal()">Cancel</button>
+      <button id="btn-cancel" nz-button nzType="default" (click)="closeModal()">{{'Cancel' | translate}}</button>
       <button id="btn-submit" nz-button nzType="primary" [disabled]="checkStatus()" (click)="submitForm()">
-          Create
+        {{'Create' | translate}}
       </button>
     </div>
   </form>
-</nz-modal>
\ No newline at end of file
+</nz-modal>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/register-model-form/register-model-tag/register-model-tags.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/register-model-form/register-model-tag/register-model-tags.component.html
index 41f695ba..bcf2c6e0 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/register-model-form/register-model-tag/register-model-tags.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/artifacts/register-model-form/register-model-tag/register-model-tags.component.html
@@ -21,7 +21,7 @@
   <submarine-model-version-tag *ngFor="let tag of tags" [tag]="tag" [type]="'editable'" [deleteTag]="deleteTag"></submarine-model-version-tag>
   <span class="addVersionTag" *ngIf="!inputVisible" (click)="showInput()">
     <i nz-icon nzType="plus"></i>
-    add tag
+    {{'add tag' | translate}}
   </span>
   <span class="addTagInput">
   <input
@@ -36,4 +36,4 @@
     (keydown.enter)="handleInputConfirm()"
   />
   </span>
-</span>
\ No newline at end of file
+</span>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/experiment-info.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/experiment-info.component.html
index e91679a9..170c7f06 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/experiment-info.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/experiment-info.component.html
@@ -29,14 +29,14 @@
   >
     <thead>
       <tr>
-        <th>Experiment Name</th>
-        <th>Experiment ID</th>
-        <th>Created Time</th>
-        <th>Running Time</th>
-        <th>Finished Time</th>
-        <th>Duration</th>
-        <th>Status</th>
-        <th>Action</th>
+        <th>{{'Experiment Name' | translate}}</th>
+        <th>{{'Experiment ID' | translate}}</th>
+        <th>{{'Created Time' | translate}}</th>
+        <th>{{'Running Time' | translate}}</th>
+        <th>{{'Finished Time' | translate}}</th>
+        <th>{{'Duration' | translate}}</th>
+        <th>{{'Status' | translate}}</th>
+        <th>{{'Action' | translate}}</th>
       </tr>
     </thead>
     <tbody>
@@ -48,28 +48,28 @@
         <td>{{ experimentInfo.finishedTime | date: 'M/d/yyyy, h:mm a' }}</td>
         <td>{{ experimentInfo.duration }}</td>
         <td>
-          <nz-tag [nzColor]="statusColor[experimentInfo.status]">{{ experimentInfo.status }}</nz-tag>
+          <nz-tag [nzColor]="statusColor[experimentInfo.status]">{{ experimentInfo.status  | translate }}</nz-tag>
         </td>
         <td class="td-action">
-          <a (click)="startExperiment()">Start</a>
+          <a (click)="startExperiment()">{{'Start' | translate}}</a>
           <nz-divider nzType="vertical"></nz-divider>
           <a nz-dropdown [nzDropdownMenu]="more">
-            More
+            {{'More' | translate}}
             <i nz-icon nzType="down"></i>
           </a>
           <nz-dropdown-menu #more="nzDropdownMenu">
             <ul nz-menu nzSelectable>
-              <li nz-menu-item (click)="editExperiment()">Edit</li>
+              <li nz-menu-item (click)="editExperiment()">{{'Edit' | translate}}</li>
               <li
                 nz-menu-item
                 nz-popconfirm
                 nzPlacement="left"
                 nzTitle="Are you sure you want to delete?"
-                nzCancelText="Cancel"
-                nzOkText="Ok"
+                nzCancelText="{{'Cancel' | translate}}"
+                nzOkText="{{'Ok' | translate}}"
                 (nzOnConfirm)="onDeleteExperiment()"
               >
-                Delete
+                {{ 'Delete' | translate }}
               </li>
             </ul>
           </nz-dropdown-menu>
@@ -88,23 +88,23 @@
       <ul nz-menu>
         <li nz-menu-item nzSelected (click)="currentState = 0">
           <i nz-icon nzType="bar-chart" nzTheme="outline"></i>
-          Charts
+          {{'Charts' | translate}}
         </li>
         <li nz-menu-item (click)="currentState = 1">
           <i nz-icon nzType="bars" nzTheme="outline"></i>
-          Parameters
+          {{'Parameters' | translate}}
         </li>
         <li nz-menu-item (click)="currentState = 2">
           <i nz-icon nzType="appstore" nzTheme="outline"></i>
-          Metrics
+          {{'Metrics' | translate}}
         </li>
         <li nz-menu-item (click)="currentState = 3">
           <i nz-icon nzType="desktop" nzTheme="outline"></i>
-          Outputs
+          {{'Outputs' | translate}}
         </li>
         <li nz-menu-item (click)="currentState = 4">
           <i nz-icon nzType="experiment" nzTheme="outline"></i>
-          Artifacts
+          {{'Artifacts' | translate}}
         </li>
       </ul>
     </nz-sider>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/hyper-params/hyper-params.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/hyper-params/hyper-params.component.html
index e4fbae18..780e18a0 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/hyper-params/hyper-params.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/hyper-params/hyper-params.component.html
@@ -18,7 +18,8 @@
   -->
 
 <div id="paramTable">
-  <nz-table #paramTable nzSize="middle" [nzBordered]="true" [nzFrontPagination]="false" [nzData]="podParam">
+  <nz-table #paramTable nzSize="middle" [nzBordered]="true" [nzFrontPagination]="false" [nzData]="podParam"
+            [nzNoResult]="'No data' | translate">
     <thead>
       <tr>
         <th>Key</th>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/metrics/metrics.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/metrics/metrics.component.html
index 17366a6f..aca241e5 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/metrics/metrics.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment-info/metrics/metrics.component.html
@@ -18,13 +18,14 @@
   -->
 
 <div id="metricTable">
-  <nz-table #metricTable nzSize="middle" [nzBordered]="true" [nzFrontPagination]="false" [nzData]="podMetric">
+  <nz-table #metricTable nzSize="middle" [nzBordered]="true" [nzFrontPagination]="false" [nzData]="podMetric"
+            [nzNoResult]="'No data' | translate">
     <thead>
       <tr>
         <th>Key</th>
         <th>Value</th>
-        <th>Time</th>
-        <th>Step</th>
+        <th>{{'Time' | translate}}</th>
+        <th>{{'Step' | translate}}</th>
       </tr>
     </thead>
     <tbody>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment.component.html
index 9a510f48..24ea5426 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment.component.html
@@ -22,10 +22,10 @@
     <div style="background-color: white; padding-left: 30px; padding-top: 20px">
       <nz-breadcrumb>
         <nz-breadcrumb-item>
-          <a>Home</a>
+          <a>{{ 'Home' | translate }}</a>
         </nz-breadcrumb-item>
         <nz-breadcrumb-item>
-          <a [routerLink]="['/', 'workbench', 'experiment']">experiment</a>
+          <a [routerLink]="['/', 'workbench', 'experiment']">{{ 'experiment' | translate }}</a>
         </nz-breadcrumb-item>
         <nz-breadcrumb-item *ngIf="experimentID != null">
           {{ experimentID }}
@@ -33,7 +33,7 @@
       </nz-breadcrumb>
       <div *ngIf="experimentID == null">
         <br />
-        <h2>Experiment</h2>
+        <h2>{{ 'Experiment' | translate }}</h2>
       </div>
       <br />
     </div>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment.module.ts b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment.module.ts
index 507a1d8c..d00b6986 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment.module.ts
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/experiment/experiment.module.ts
@@ -22,25 +22,28 @@ import { NgModule } from '@angular/core';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { RouterModule } from '@angular/router';
 import { PipeSharedModule } from '@submarine/pipe/pipe-shared.module';
+import { ExperimentService } from '@submarine/services/experiment.service';
 import { NgxChartsModule } from '@swimlane/ngx-charts';
 import { NgZorroAntdModule } from 'ng-zorro-antd';
-import { ExperimentComponent } from './experiment.component';
+import { ModelModule } from '../model/model.module';
+import { ExperimentCustomizedFormComponent } from './experiment-home/experiment-form/experiment-customized-form/experiment-customized-form.component';
+import { ExperimentFormComponent } from './experiment-home/experiment-form/experiment-form.component';
+import { ExperimentPredefinedFormComponent } from './experiment-home/experiment-form/experiment-predefined-form/experiment-predefined-form.component';
+import { ExperimentHomeComponent } from './experiment-home/experiment-home.component';
 import { ExperimentListComponent } from './experiment-home/experiment-list/experiment-list.component';
-import { ExperimentRoutingModule } from './experiment-routing.module';
+import { ArtifactsComponent } from './experiment-info/artifacts/artifacts.component';
+import { RegisterModelFormComponent } from './experiment-info/artifacts/register-model-form/register-model-form.component';
+import { RegisterModelTagsComponent } from './experiment-info/artifacts/register-model-form/register-model-tag/register-model-tags.component';
+import { ChartsComponent } from './experiment-info/charts/charts.component';
 import { ExperimentInfoComponent } from './experiment-info/experiment-info.component';
 import { HyperParamsComponent } from './experiment-info/hyper-params/hyper-params.component';
 import { MetricsComponent } from './experiment-info/metrics/metrics.component';
-import { ChartsComponent } from './experiment-info/charts/charts.component';
 import { OutputsComponent } from './experiment-info/outputs/outputs.component';
-import { ArtifactsComponent } from './experiment-info/artifacts/artifacts.component';
-import { ExperimentHomeComponent } from './experiment-home/experiment-home.component';
-import { ExperimentService } from '@submarine/services/experiment.service';
-import { ExperimentFormComponent } from './experiment-home/experiment-form/experiment-form.component';
-import { ExperimentPredefinedFormComponent } from './experiment-home/experiment-form/experiment-predefined-form/experiment-predefined-form.component';
-import { ExperimentCustomizedFormComponent } from './experiment-home/experiment-form/experiment-customized-form/experiment-customized-form.component';
-import { RegisterModelFormComponent } from './experiment-info/artifacts/register-model-form/register-model-form.component';
-import { RegisterModelTagsComponent } from './experiment-info/artifacts/register-model-form/register-model-tag/register-model-tags.component';
-import { ModelModule } from '../model/model.module';
+import { ExperimentRoutingModule } from './experiment-routing.module';
+import { ExperimentComponent } from './experiment.component';
+
+import { TranslateModule } from '@ngx-translate/core';
+import TRANSLATE_CONFIG from "@submarine/core/local-translate";
 
 @NgModule({
   exports: [ExperimentComponent],
@@ -53,7 +56,8 @@ import { ModelModule } from '../model/model.module';
     RouterModule,
     PipeSharedModule,
     ExperimentRoutingModule,
-    ModelModule
+    ModelModule,
+    TranslateModule.forChild(TRANSLATE_CONFIG)
   ],
   providers: [ExperimentService],
   declarations: [
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.html b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.html
index e5cb8fb4..5190577f 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.html
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.html
@@ -33,10 +33,10 @@
   </div>
   <ul nz-menu nzTheme="dark" nzMode="inline" [nzInlineCollapsed]="isCollapsed">
     <ng-container *ngFor="let menu of menus">
-      <li *ngIf="menu.children" nz-submenu [nzDisabled]="menu.disabled" [nzTitle]="menu.title" [nzIcon]="menu.iconType">
+      <li *ngIf="menu.children" nz-submenu [nzDisabled]="menu.disabled" [nzTitle]="menu.title | translate" [nzIcon]="menu.iconType">
         <ul>
           <li nz-menu-item nzMatchRouter [nzDisabled]="menu.disabled" *ngFor="let subItem of menu.children">
-            <a [routerLink]="subItem.routerLink">{{ subItem.title }}</a>
+            <a [routerLink]="subItem.routerLink">{{ subItem.title | translate }}</a>
           </li>
         </ul>
       </li>
@@ -45,13 +45,13 @@
         nz-menu-item
         nz-tooltip
         [nzDisabled]="menu.disabled"
-        [nzTitle]="menu.title"
+        [nzTitle]="menu.title | translate"
         nzPlacement="right"
         nzMatchRouter
         [routerLink]="menu.routerLink"
       >
         <i nz-icon [nzType]="menu.iconType"></i>
-        <span>{{ menu.title }}</span>
+        <span>{{ menu.title | translate }}</span>
       </li>
     </ng-container>
   </ul>
@@ -63,26 +63,46 @@
         <i class="trigger" nz-icon [nzType]="isCollapsed ? 'menu-unfold' : 'menu-fold'"></i>
       </div>
 
-      <div class="header-operation">
+      <div class="header-operation" >
+
+        <div
+          nz-dropdown
+          [nzDropdownMenu]="languageMenu"
+          class="inner-header-operation"
+        >
+           {{ 'Language' | translate }}
+        </div>
+        <nz-dropdown-menu #languageMenu="nzDropdownMenu">
+          <ul nz-menu>
+            <li nz-menu-item (click)="setLang('zh-cn')">
+              简体中文
+            </li>
+            <li nz-menu-divider></li>
+            <li nz-menu-item (click)="setLang('en')">
+              English
+            </li>
+          </ul>
+        </nz-dropdown-menu>
+
         <div
           nz-dropdown
           *ngIf="userInfo$ | async as userInfo"
           [nzDropdownMenu]="userInfoMenu"
-          class="operation-user-info"
+          class="operation-user-info inner-header-operation"
         >
           <nz-avatar nzIcon="user" nzSize="small"></nz-avatar>
-          {{ userInfo.name }}
+          {{ userInfo.name }}
         </div>
         <nz-dropdown-menu #userInfoMenu="nzDropdownMenu">
           <ul nz-menu>
             <li nz-menu-item nzDisabled>
               <i nz-icon nzType="setting"></i>
-              UserInfo setting
+              {{ 'UserInfo setting' | translate }}
             </li>
             <li nz-menu-divider></li>
             <li nz-menu-item (click)="logout()">
               <i nz-icon nzType="logout"></i>
-              Sign out
+              {{ 'Sign out' | translate }}
             </li>
           </ul>
         </nz-dropdown-menu>
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.scss b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.scss
index 486c21f1..ec2155da 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.scss
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.scss
@@ -94,6 +94,11 @@ nz-header {
   justify-content: space-between;
 }
 
+.inner-header-operation {
+  padding: 0 0 0 24px;
+  float:left;
+}
+
 nz-content {
   margin: 24px;
 }
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.ts b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.ts
index f177201b..2d00e3f5 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.ts
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.component.ts
@@ -17,13 +17,14 @@
  * under the License.
  */
 
-import { Component, OnInit } from '@angular/core';
-import { Router } from '@angular/router';
-import { UserInfo } from '@submarine/interfaces';
-import { AuthService, UserService } from '@submarine/services';
-import { NzNotificationService } from 'ng-zorro-antd';
-import { Observable } from 'rxjs';
-import { tap } from 'rxjs/operators';
+import {Component, OnInit} from '@angular/core';
+import {Router} from '@angular/router';
+import {TranslateService} from '@ngx-translate/core';
+import {UserInfo} from '@submarine/interfaces';
+import {AuthService, UserService} from '@submarine/services';
+import {NzNotificationService} from 'ng-zorro-antd';
+import {Observable} from 'rxjs';
+import {tap} from 'rxjs/operators';
 
 interface SidebarMenu {
   title: string;
@@ -129,14 +130,26 @@ export class WorkbenchComponent implements OnInit {
     private router: Router,
     private authService: AuthService,
     private userService: UserService,
-    private nzNotificationService: NzNotificationService
-  ) {}
+    private nzNotificationService: NzNotificationService,
+    private translate: TranslateService
+  ) {
+  }
+
+  setLang(lang: string) {
+    // change language
+    this.translate.use(lang);
+    console.log(`change language to ${lang}`)
+    // save to localStorage in order to refresh the page can correctly display the language
+    localStorage.setItem('translate', lang);
+  }
 
   ngOnInit() {
     if (this.authService.isLoggedIn) {
       this.userInfo$ = this.userService.fetchUserInfo().pipe(
         tap((userInfo) => {
-          this.nzNotificationService.success('Welcome', `Welcome back, ${userInfo.name}`);
+          this.nzNotificationService.success(this.translate.instant('Welcome'),
+            `${this.translate.instant('Welcome back')}, ${userInfo.name}`
+          );
         })
       );
     }
diff --git a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.module.ts b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.module.ts
index c3644717..541fa5a7 100644
--- a/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.module.ts
+++ b/submarine-workbench/workbench-web/src/app/pages/workbench/workbench.module.ts
@@ -37,6 +37,8 @@ import { EnvironmentModule } from './environment/environment.module';
 import { TemplateModule } from './template/template.module';
 import { ModelModule } from './model/model.module';
 
+import { TranslateModule } from '@ngx-translate/core';
+import TRANSLATE_CONFIG from "@submarine/core/local-translate";
 
 @NgModule({
   declarations: [WorkbenchComponent, HomeComponent, WorkspaceComponent, DataComponent],
@@ -55,6 +57,7 @@ import { ModelModule } from './model/model.module';
     EnvironmentModule,
     TemplateModule,
     ModelModule,
+    TranslateModule.forRoot(TRANSLATE_CONFIG)
   ],
 })
 export class WorkbenchModule {}
diff --git a/submarine-workbench/workbench-web/src/assets/i18n/en.json b/submarine-workbench/workbench-web/src/assets/i18n/en.json
new file mode 100644
index 00000000..9b0116ae
--- /dev/null
+++ b/submarine-workbench/workbench-web/src/assets/i18n/en.json
@@ -0,0 +1,83 @@
+{
+  "Language": "Language",
+  "Welcome": "Welcome",
+  "UserInfo setting": "UserInfo setting",
+  "Sign out": "Sign out",
+  "Welcome back": "Welcome back",
+  "Home": "Home",
+  "Template": "Template",
+  "Experiment": "Experiment",
+  "Environment": "Environment",
+  "Manager": "Manager",
+  "User": "User",
+  "Department": "Department",
+  "Model": "Model",
+  "Data": "Data",
+  "Workspace": "Workspace",
+  "experiment": "experiment",
+  "Auto Reload": "Auto Reload",
+  "Experiment Name": "Experiment Name",
+  "Experiment ID": "Experiment ID",
+  "Tags": "Tags",
+  "Status": "Status",
+  "Finished Time": "Finished Time",
+  "Created Time": "Created Time",
+  "Running Time": "Running Time",
+  "Duration": "Duration",
+  "Action": "Action",
+  "Clone": "Clone",
+  "Update": "Update",
+  "Delete": "Delete",
+  "Are you sure you want to delete?": "Are you sure you want to delete?",
+  "Ok": "Ok",
+  "Cancel": "Cancel",
+  "All": "All",
+  "Owned By Me": "Owned By Me",
+  "Accessible By Me": "Accessible By Me",
+  "input search text": "input search text",
+  "New Experiment": "New Experiment",
+  "Create Experiment": "Create Experiment",
+  "Confirm to delete?": "Confirm to delete?",
+  "Define your experiment": "Define your experiment",
+  "From predefined experiment library": "From predefined experiment library",
+  "Prev Step": "Prev Step",
+  "Next step": "Next step",
+  "Submit": "Submit",
+  "First Step": "First Step",
+  "Second Step": "Second Step",
+  "Preview": "Preview",
+  "Only letters(a - z), numbers(0 - 9), and hyphens are allowed, but you can`t start or end with hyphens.": "Only letters(a - z), numbers(0 - 9), and hyphens are allowed, but you can`t start or end with hyphens.",
+  "Description": "Description",
+  "Run distributed mnist example": "Run distributed mnist example",
+  "Command": "Command",
+  "Image": "Image",
+  "Add item": "Add item",
+  "Advanced": "Advanced",
+  "Copy git repo to /code/current in container.": "Copy git repo to /code/current in container.",
+  "Add new environment variable": "Add new environment variable",
+  "predefined-template": "predefined-template",
+  "Please select templates.": "Please select templates.",
+  "Select a predefined experiment template": "Select a predefined experiment template",
+  "Configurable Parameters": "Configurable Parameters",
+  "Name": "Name",
+  "Namespace": "Namespace",
+  "Environment Variables": "Environment Variables",
+  "Start": "Start",
+  "More": "More",
+  "Edit": "Edit",
+  "Accepted": "Accepted",
+  "Created": "Created",
+  "Running": "Running",
+  "Succeeded": "Succeeded",
+  "Charts": "Charts",
+  "Parameters": "Parameters",
+  "Metrics": "Metrics",
+  "Outputs": "Outputs",
+  "Time": "Time",
+  "Step": "Step",
+  "Register model": "Register model",
+  "Create": "Create",
+  "Model Name": "Model Name",
+  "add tag": "add tag",
+  "No data": "No data"
+}
diff --git a/submarine-workbench/workbench-web/src/assets/i18n/zh-cn.json b/submarine-workbench/workbench-web/src/assets/i18n/zh-cn.json
new file mode 100644
index 00000000..26b9cfa0
--- /dev/null
+++ b/submarine-workbench/workbench-web/src/assets/i18n/zh-cn.json
@@ -0,0 +1,83 @@
+{
+  "Language": "语言",
+  "Welcome": "欢迎",
+  "UserInfo setting": "用户信息配置",
+  "Sign out": "登出",
+  "Welcome back": "欢迎回来",
+  "Home": "主页",
+  "Template": "模板",
+  "Experiment": "实验",
+  "Environment": "环境",
+  "Manager": "管理",
+  "User": "用户",
+  "Department": "部门",
+  "Model": "模型",
+  "Data": "数据",
+  "Workspace": "工作空间",
+  "experiment": "实验",
+  "Auto Reload": "自动刷新",
+  "Experiment Name": "实验名称",
+  "Experiment ID": "实验ID",
+  "Tags": "标签",
+  "Status": "状态",
+  "Finished Time": "完成时间",
+  "Created Time": "创建时间",
+  "Running Time": "运行时间",
+  "Duration": "持续时间",
+  "Action": "操作",
+  "Clone": "克隆",
+  "Update": "更新",
+  "Delete": "删除",
+  "Are you sure you want to delete?": "您确认想要删除吗?",
+  "Ok": "确认",
+  "Cancel": "取消",
+  "All": "全部",
+  "Owned By Me": "属于我的",
+  "Accessible By Me": "我可以访问的",
+  "input search text": "输入搜索文本",
+  "New Experiment": "新增实验",
+  "Create Experiment": "创建实验",
+  "Confirm to delete?": "确认删除吗?",
+  "Define your experiment": "定义您的实验",
+  "From predefined experiment library": "预定义实验库",
+  "Prev Step": "上一步",
+  "Next step": "下一步",
+  "Submit": "提交",
+  "First Step": "第一步",
+  "Second Step": "第二步",
+  "Preview": "预览",
+  "Only letters(a - z), numbers(0 - 9), and hyphens are allowed, but you can`t start or end with hyphens.": "只允许使用字母(a-z)、数字(0-9)和连字符,但不能以连字符开头或结尾。",
+  "Description": "描述",
+  "Run distributed mnist example": "运行分布式mnist示例",
+  "Command": "命令",
+  "Image": "镜像",
+  "Add item": "添加项目",
+  "Advanced": "进阶",
+  "Copy git repo to /code/current in container.": "将 git repo 拷贝到容器中 /code/current 路径",
+  "Add new environment variable": "添加新的环境变量",
+  "predefined-template": "预定义模板",
+  "Please select templates.": "请选择模板",
+  "Select a predefined experiment template": "请选择模板",
+  "Configurable Parameters": "配置参数",
+  "Name": "名称",
+  "Namespace": "命名空间",
+  "Environment Variables": "环境变量",
+  "Start": "启动",
+  "More": "更多",
+  "Edit": "编译",
+  "Accepted": "已接收",
+  "Created": "已创建",
+  "Running": "运行中",
+  "Succeeded": "成功",
+  "Charts": "图表",
+  "Parameters": "参数",
+  "Metrics": "指标",
+  "Outputs": "输出",
+  "Time": "时间",
+  "Step": "阶段",
+  "Register model": "注册模型",
+  "Create": "创建",
+  "Model Name": "模型名称",
+  "add tag": "添加标签",
+  "No data": "没有数据"
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@submarine.apache.org
For additional commands, e-mail: dev-help@submarine.apache.org