mirror of
https://github.com/goharbor/harbor
synced 2024-09-21 00:24:31 +00:00
Merge pull request #11834 from AllForNothing/release-2.0.0
[Cherry-pick]Improve i18n service
This commit is contained in:
commit
d248a7b132
|
@ -25,6 +25,7 @@ COPY src/portal /build_dir
|
||||||
|
|
||||||
ENV NPM_CONFIG_REGISTRY=${npm_registry}
|
ENV NPM_CONFIG_REGISTRY=${npm_registry}
|
||||||
RUN npm install --unsafe-perm
|
RUN npm install --unsafe-perm
|
||||||
|
RUN npm run generate-build-timestamp
|
||||||
RUN node --max_old_space_size=2048 'node_modules/@angular/cli/bin/ng' build --prod
|
RUN node --max_old_space_size=2048 'node_modules/@angular/cli/bin/ng' build --prod
|
||||||
|
|
||||||
FROM ${harbor_base_namespace}/harbor-portal-base:${harbor_base_image_version}
|
FROM ${harbor_base_namespace}/harbor-portal-base:${harbor_base_image_version}
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
"build": "ng build --aot",
|
"build": "ng build --aot",
|
||||||
"release": "ng build --prod",
|
"release": "ng build --prod",
|
||||||
"build-mock-api-server": "tsc -p server",
|
"build-mock-api-server": "tsc -p server",
|
||||||
"mock-api-server": "npm run build-mock-api-server && node server/dist/server/src/mock-api.js"
|
"mock-api-server": "npm run build-mock-api-server && node server/dist/server/src/mock-api.js",
|
||||||
|
"generate-build-timestamp": "node scripts/generate-build-timestamp.js"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
19
src/portal/scripts/generate-build-timestamp.js
Normal file
19
src/portal/scripts/generate-build-timestamp.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* generate timestamp for each production build
|
||||||
|
*/
|
||||||
|
const fs = require('fs');
|
||||||
|
const data = fs.readFileSync('src/environments/environment.prod.ts', 'utf8').split('\n');
|
||||||
|
|
||||||
|
let buildTimestampIndex = 0;
|
||||||
|
data.forEach((item,index) => {
|
||||||
|
if(item.indexOf('buildTimestamp') !== -1) {
|
||||||
|
buildTimestampIndex = index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (buildTimestampIndex > 0) {
|
||||||
|
const timestamp = new Date().getTime();
|
||||||
|
data[buildTimestampIndex] = ` buildTimestamp: ${timestamp},`;
|
||||||
|
fs.writeFileSync('src/environments/environment.prod.ts', data.join('\n'), 'utf8');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,19 +81,15 @@
|
||||||
</clr-vertical-nav-group>
|
</clr-vertical-nav-group>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="vertical-nav-footer">
|
<ng-container *ngFor="let theme of themeArray;let i=index">
|
||||||
<ng-container *ngFor="let theme of themeArray;let i=index">
|
<ng-container *ngIf="theme.showStyle === styleMode">
|
||||||
<ng-container *ngIf="theme.showStyle === styleMode">
|
<a clrVerticalNavLink (click)="themeChanged(theme)">
|
||||||
<a class="nav-link nav-icon theme-select"
|
<clr-icon clrVerticalNavIcon size="20" *ngIf="styleMode ==='DARK'" shape="sun" class="is-solid"></clr-icon>
|
||||||
(click)="themeChanged(theme)">
|
<clr-icon clrVerticalNavIcon size="20" *ngIf="styleMode ==='LIGHT'" shape="moon" class="is-solid"></clr-icon>
|
||||||
<clr-icon size="20" *ngIf="styleMode ==='DARK'" shape="sun" class="is-solid"></clr-icon>
|
|
||||||
<clr-icon size="20" *ngIf="styleMode ==='LIGHT'" shape="moon" class="is-solid"></clr-icon>
|
|
||||||
{{ theme.text | translate }}
|
{{ theme.text | translate }}
|
||||||
</a>
|
</a>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
|
||||||
|
|
||||||
<clr-vertical-nav-group routerLinkActive="active">
|
<clr-vertical-nav-group routerLinkActive="active">
|
||||||
<clr-icon shape="network-globe" clrVerticalNavIcon></clr-icon>
|
<clr-icon shape="network-globe" clrVerticalNavIcon></clr-icon>
|
||||||
{{'SIDE_NAV.API_EXPLORER' | translate}}
|
{{'SIDE_NAV.API_EXPLORER' | translate}}
|
||||||
|
|
|
@ -32,22 +32,6 @@ clr-vertical-nav {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.vertical-nav-footer {
|
|
||||||
margin: 5px 23px;
|
|
||||||
a {
|
|
||||||
display: inline-block;
|
|
||||||
line-height: 0;
|
|
||||||
padding: 0;
|
|
||||||
height: 24px;
|
|
||||||
&:hover {
|
|
||||||
background: transparent;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
.api-button {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.font-size-13 {
|
.font-size-13 {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
@ -82,23 +66,3 @@ clr-vertical-nav {
|
||||||
.right {
|
.right {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.theme-select {
|
|
||||||
width: 5.4rem;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
height: 100%;
|
|
||||||
font-size: 14px;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
clr-icon {
|
|
||||||
position: static;
|
|
||||||
transform: none;
|
|
||||||
margin-right: .2rem;
|
|
||||||
min-width: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,7 +29,12 @@
|
||||||
<clr-dg-column [clrDgField]="'version'">{{'VULNERABILITY.GRID.COLUMN_VERSION' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgField]="'version'">{{'VULNERABILITY.GRID.COLUMN_VERSION' | translate}}</clr-dg-column>
|
||||||
<clr-dg-column [clrDgField]="'fix_version'">{{'VULNERABILITY.GRID.COLUMN_FIXED' | translate}}</clr-dg-column>
|
<clr-dg-column [clrDgField]="'fix_version'">{{'VULNERABILITY.GRID.COLUMN_FIXED' | translate}}</clr-dg-column>
|
||||||
|
|
||||||
<clr-dg-placeholder>{{'VULNERABILITY.CHART.TOOLTIPS_TITLE_ZERO' | translate}}</clr-dg-placeholder>
|
<clr-dg-placeholder>
|
||||||
|
<span *ngIf="hasScanned();else elseBlock">{{'VULNERABILITY.STATE.OTHER_STATUS' | translate}}</span>
|
||||||
|
<ng-template #elseBlock>
|
||||||
|
{{'VULNERABILITY.CHART.TOOLTIPS_TITLE_ZERO' | translate}}
|
||||||
|
</ng-template>
|
||||||
|
</clr-dg-placeholder>
|
||||||
<clr-dg-row *clrDgItems="let res of scanningResults">
|
<clr-dg-row *clrDgItems="let res of scanningResults">
|
||||||
<clr-dg-cell>
|
<clr-dg-cell>
|
||||||
<span *ngIf="!res.links || res.links.length === 0">{{res.id}}</span>
|
<span *ngIf="!res.links || res.links.length === 0">{{res.id}}</span>
|
||||||
|
|
|
@ -181,6 +181,13 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
|
||||||
return this.hasViewInitWithDelay && this.resultBarChartComponent
|
return this.hasViewInitWithDelay && this.resultBarChartComponent
|
||||||
&& (this.resultBarChartComponent.queued || this.resultBarChartComponent.scanning || this.resultBarChartComponent.error);
|
&& (this.resultBarChartComponent.queued || this.resultBarChartComponent.scanning || this.resultBarChartComponent.error);
|
||||||
}
|
}
|
||||||
|
hasScanned(): boolean {
|
||||||
|
return this.hasViewInitWithDelay && this.resultBarChartComponent
|
||||||
|
&& !(this.resultBarChartComponent.completed
|
||||||
|
|| this.resultBarChartComponent.error
|
||||||
|
|| this.resultBarChartComponent.queued
|
||||||
|
|| this.resultBarChartComponent.scanning);
|
||||||
|
}
|
||||||
handleScanOverview(scanOverview: any): any {
|
handleScanOverview(scanOverview: any): any {
|
||||||
if (scanOverview) {
|
if (scanOverview) {
|
||||||
return scanOverview[DEFAULT_SUPPORTED_MIME_TYPE];
|
return scanOverview[DEFAULT_SUPPORTED_MIME_TYPE];
|
||||||
|
|
|
@ -12,5 +12,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: true
|
production: true,
|
||||||
|
buildTimestamp: 0,
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,5 +17,6 @@
|
||||||
// The list of which env maps to which file can be found in `angular-cli.json`.
|
// The list of which env maps to which file can be found in `angular-cli.json`.
|
||||||
|
|
||||||
export const environment = {
|
export const environment = {
|
||||||
production: false
|
production: false,
|
||||||
|
buildTimestamp: 0,
|
||||||
};
|
};
|
||||||
|
|
|
@ -997,7 +997,7 @@
|
||||||
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
||||||
"TOOLTIPS_TITLE": "{{totalVulnerability}} of {{totalPackages}} {{package}} have known {{vulnerability}}.",
|
"TOOLTIPS_TITLE": "{{totalVulnerability}} of {{totalPackages}} {{package}} have known {{vulnerability}}.",
|
||||||
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} of {{totalPackages}} {{package}} has known {{vulnerability}}.",
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} of {{totalPackages}} {{package}} has known {{vulnerability}}.",
|
||||||
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability found"
|
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability detected"
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"CRITICAL": "Critical",
|
"CRITICAL": "Critical",
|
||||||
|
|
|
@ -997,7 +997,7 @@
|
||||||
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
||||||
"TOOLTIPS_TITLE": "{{totalVulnerability}} of {{totalPackages}} {{package}} have known {{vulnerability}}.",
|
"TOOLTIPS_TITLE": "{{totalVulnerability}} of {{totalPackages}} {{package}} have known {{vulnerability}}.",
|
||||||
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} of {{totalPackages}} {{package}} has known {{vulnerability}}.",
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} of {{totalPackages}} {{package}} has known {{vulnerability}}.",
|
||||||
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability found"
|
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability detected"
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"CRITICAL": "Critical",
|
"CRITICAL": "Critical",
|
||||||
|
|
|
@ -970,7 +970,7 @@
|
||||||
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
||||||
"TOOLTIPS_TITLE": "{{totalVulnerability}} de {{totalPackages}} {{package}} ont des {{vulnerability}} connues.",
|
"TOOLTIPS_TITLE": "{{totalVulnerability}} de {{totalPackages}} {{package}} ont des {{vulnerability}} connues.",
|
||||||
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} de {{totalPackages}} {{package}} a des {{vulnerability}} connues.",
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} de {{totalPackages}} {{package}} a des {{vulnerability}} connues.",
|
||||||
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability found"
|
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability detected"
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"CRITICAL": "Critique",
|
"CRITICAL": "Critique",
|
||||||
|
|
|
@ -993,7 +993,7 @@
|
||||||
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
||||||
"TOOLTIPS_TITLE": "{{totalVulnerability}} de {{totalPackages}} {{package}} possuem {{vulnerability}}.",
|
"TOOLTIPS_TITLE": "{{totalVulnerability}} de {{totalPackages}} {{package}} possuem {{vulnerability}}.",
|
||||||
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} de {{totalPackages}} {{package}} possuem {{vulnerability}}.",
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} de {{totalPackages}} {{package}} possuem {{vulnerability}}.",
|
||||||
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability found"
|
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability detected"
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"CRITICAL": "Crítico",
|
"CRITICAL": "Crítico",
|
||||||
|
|
|
@ -997,7 +997,7 @@
|
||||||
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
"SCANNING_PERCENT_EXPLAIN": "Scan completed percentage is calculated as # of successfully scanned images / total number of images referenced within the image index.",
|
||||||
"TOOLTIPS_TITLE": "{{totalVulnerability}} 'nın {{totalPackages}} {{package}} bilinen {{vulnerability}}.",
|
"TOOLTIPS_TITLE": "{{totalVulnerability}} 'nın {{totalPackages}} {{package}} bilinen {{vulnerability}}.",
|
||||||
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} 'nın {{totalPackages}} {{package}} bilinen {{vulnerability}}.",
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalVulnerability}} 'nın {{totalPackages}} {{package}} bilinen {{vulnerability}}.",
|
||||||
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability found"
|
"TOOLTIPS_TITLE_ZERO": "No recognizable vulnerability detected"
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"CRITICAL": "Kritik",
|
"CRITICAL": "Kritik",
|
||||||
|
|
|
@ -997,7 +997,7 @@
|
||||||
"SCANNING_PERCENT_EXPLAIN": "扫描完成度是扫描成功的镜像数与总共需要扫描的镜像数的比值,总共需要的扫描的镜像不包含 Index 。",
|
"SCANNING_PERCENT_EXPLAIN": "扫描完成度是扫描成功的镜像数与总共需要扫描的镜像数的比值,总共需要的扫描的镜像不包含 Index 。",
|
||||||
"TOOLTIPS_TITLE": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}。",
|
"TOOLTIPS_TITLE": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}。",
|
||||||
"TOOLTIPS_TITLE_SINGULAR": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}。",
|
"TOOLTIPS_TITLE_SINGULAR": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}。",
|
||||||
"TOOLTIPS_TITLE_ZERO": "没有发现可识别的漏洞"
|
"TOOLTIPS_TITLE_ZERO": "没有检测到可识别的漏洞"
|
||||||
},
|
},
|
||||||
"SEVERITY": {
|
"SEVERITY": {
|
||||||
"CRITICAL": "危急",
|
"CRITICAL": "危急",
|
||||||
|
|
|
@ -102,10 +102,6 @@ h4 {
|
||||||
top: 8px;
|
top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-solid {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selectBox {
|
.selectBox {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -11,11 +11,15 @@ import { TranslateHttpLoader } from "@ngx-translate/http-loader";
|
||||||
import { MyMissingTranslationHandler } from "../../i18n/missing-trans.handler";
|
import { MyMissingTranslationHandler } from "../../i18n/missing-trans.handler";
|
||||||
import { TranslatorJsonLoader } from "../../i18n/local-json.loader";
|
import { TranslatorJsonLoader } from "../../i18n/local-json.loader";
|
||||||
import { ClipboardModule } from "../../components/third-party/ngx-clipboard";
|
import { ClipboardModule } from "../../components/third-party/ngx-clipboard";
|
||||||
|
import { environment } from '../../../environments/environment';
|
||||||
|
|
||||||
export function GeneralTranslatorLoader(http: HttpClient, config: IServiceConfig) {
|
export function GeneralTranslatorLoader(http: HttpClient, config: IServiceConfig) {
|
||||||
if (config && config.langMessageLoader === 'http') {
|
if (config && config.langMessageLoader === 'http') {
|
||||||
let prefix: string = config.langMessagePathForHttpLoader ? config.langMessagePathForHttpLoader : "i18n/lang/";
|
const prefix: string = config.langMessagePathForHttpLoader ? config.langMessagePathForHttpLoader : "i18n/lang/";
|
||||||
let suffix: string = config.langMessageFileSuffixForHttpLoader ? config.langMessageFileSuffixForHttpLoader : "-lang.json";
|
let suffix: string = config.langMessageFileSuffixForHttpLoader ? config.langMessageFileSuffixForHttpLoader : "-lang.json";
|
||||||
|
if (environment && environment.buildTimestamp) {
|
||||||
|
suffix += `?buildTimeStamp=${environment.buildTimestamp}`;
|
||||||
|
}
|
||||||
return new TranslateHttpLoader(http, prefix, suffix);
|
return new TranslateHttpLoader(http, prefix, suffix);
|
||||||
} else {
|
} else {
|
||||||
return new TranslatorJsonLoader(config);
|
return new TranslatorJsonLoader(config);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user