mirror of
https://github.com/goharbor/harbor
synced 2024-09-20 19:17:40 +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}
|
||||
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
|
||||
|
||||
FROM ${harbor_base_namespace}/harbor-portal-base:${harbor_base_image_version}
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
"build": "ng build --aot",
|
||||
"release": "ng build --prod",
|
||||
"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,
|
||||
"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>
|
||||
</div>
|
||||
<div>
|
||||
<div class="vertical-nav-footer">
|
||||
<ng-container *ngFor="let theme of themeArray;let i=index">
|
||||
<ng-container *ngIf="theme.showStyle === styleMode">
|
||||
<a class="nav-link nav-icon theme-select"
|
||||
(click)="themeChanged(theme)">
|
||||
<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>
|
||||
<ng-container *ngFor="let theme of themeArray;let i=index">
|
||||
<ng-container *ngIf="theme.showStyle === styleMode">
|
||||
<a clrVerticalNavLink (click)="themeChanged(theme)">
|
||||
<clr-icon clrVerticalNavIcon size="20" *ngIf="styleMode ==='DARK'" shape="sun" class="is-solid"></clr-icon>
|
||||
<clr-icon clrVerticalNavIcon size="20" *ngIf="styleMode ==='LIGHT'" shape="moon" class="is-solid"></clr-icon>
|
||||
{{ theme.text | translate }}
|
||||
</a>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<clr-vertical-nav-group routerLinkActive="active">
|
||||
<clr-icon shape="network-globe" clrVerticalNavIcon></clr-icon>
|
||||
{{'SIDE_NAV.API_EXPLORER' | translate}}
|
||||
|
|
|
@ -32,22 +32,6 @@ clr-vertical-nav {
|
|||
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: 13px;
|
||||
|
@ -82,23 +66,3 @@ clr-vertical-nav {
|
|||
.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]="'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-cell>
|
||||
<span *ngIf="!res.links || res.links.length === 0">{{res.id}}</span>
|
||||
|
@ -73,4 +78,4 @@
|
|||
</clr-dg-footer>
|
||||
</clr-datagrid>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -181,6 +181,13 @@ export class ArtifactVulnerabilitiesComponent implements OnInit, OnDestroy {
|
|||
return this.hasViewInitWithDelay && this.resultBarChartComponent
|
||||
&& (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 {
|
||||
if (scanOverview) {
|
||||
return scanOverview[DEFAULT_SUPPORTED_MIME_TYPE];
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
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`.
|
||||
|
||||
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.",
|
||||
"TOOLTIPS_TITLE": "{{totalVulnerability}} of {{totalPackages}} {{package}} have 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": {
|
||||
"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.",
|
||||
"TOOLTIPS_TITLE": "{{totalVulnerability}} of {{totalPackages}} {{package}} have 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": {
|
||||
"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.",
|
||||
"TOOLTIPS_TITLE": "{{totalVulnerability}} de {{totalPackages}} {{package}} ont 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": {
|
||||
"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.",
|
||||
"TOOLTIPS_TITLE": "{{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": {
|
||||
"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.",
|
||||
"TOOLTIPS_TITLE": "{{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": {
|
||||
"CRITICAL": "Kritik",
|
||||
|
|
|
@ -997,7 +997,7 @@
|
|||
"SCANNING_PERCENT_EXPLAIN": "扫描完成度是扫描成功的镜像数与总共需要扫描的镜像数的比值,总共需要的扫描的镜像不包含 Index 。",
|
||||
"TOOLTIPS_TITLE": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}。",
|
||||
"TOOLTIPS_TITLE_SINGULAR": "{{totalPackages}}个{{package}}中的{{totalVulnerability}}个含有{{vulnerability}}。",
|
||||
"TOOLTIPS_TITLE_ZERO": "没有发现可识别的漏洞"
|
||||
"TOOLTIPS_TITLE_ZERO": "没有检测到可识别的漏洞"
|
||||
},
|
||||
"SEVERITY": {
|
||||
"CRITICAL": "危急",
|
||||
|
|
|
@ -102,10 +102,6 @@ h4 {
|
|||
top: 8px;
|
||||
}
|
||||
|
||||
.is-solid {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selectBox {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
@ -296,4 +292,4 @@ clr-modal {
|
|||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,11 +11,15 @@ import { TranslateHttpLoader } from "@ngx-translate/http-loader";
|
|||
import { MyMissingTranslationHandler } from "../../i18n/missing-trans.handler";
|
||||
import { TranslatorJsonLoader } from "../../i18n/local-json.loader";
|
||||
import { ClipboardModule } from "../../components/third-party/ngx-clipboard";
|
||||
import { environment } from '../../../environments/environment';
|
||||
|
||||
export function GeneralTranslatorLoader(http: HttpClient, config: IServiceConfig) {
|
||||
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";
|
||||
if (environment && environment.buildTimestamp) {
|
||||
suffix += `?buildTimeStamp=${environment.buildTimestamp}`;
|
||||
}
|
||||
return new TranslateHttpLoader(http, prefix, suffix);
|
||||
} else {
|
||||
return new TranslatorJsonLoader(config);
|
||||
|
|
Loading…
Reference in New Issue
Block a user