diff --git a/src/ui_ng/lib/README.md b/src/ui_ng/lib/README.md index e3228faa4..7546a20fe 100644 --- a/src/ui_ng/lib/README.md +++ b/src/ui_ng/lib/README.md @@ -51,6 +51,7 @@ If no parameters are passed to **'forRoot'**, the module will be initialized wit **Enable components via tags** * **Registry log view** + ``` //No @Input properties @@ -58,27 +59,32 @@ If no parameters are passed to **'forRoot'**, the module will be initialized wit ``` * **Replication Management View** +Support two different display scope mode: under specific project or whole system. + +If **projectId** is set to the id of specified project, then only show the replication rules bound with the project. Otherwise, show all the rules of the whole system. + +**withReplicationJob** is used to determine whether or not show the replication jobs which are relevant with the selected replication rule. + ``` - + ``` * **Endpoint Management View** ``` +//No @Input properties + ``` -* **Repository and Tag Management View** -``` -/* -export interface SessionInfo { - withNotary?: boolean; - hasProjectAdminRole?: boolean; - hasSignedIn?: boolean; - registryUrl?: string; -} -*/ +* **Repository and Tag Management View[updating]** +**projectId** is used to specify which projects the repositories are from. - +**hasSignedIn** is a user session related property to determined whether a valid user signed in session existing. This component supports anonymous user. + +**hasProjectAdminRole** is a user session related property to determined whether the current user has project administrator role. Some action menus might be disabled based on this property. + +``` + ``` ## Configurations @@ -88,14 +94,20 @@ All the related configurations are defined in the **HarborModuleConfig** interfa The base configuration for the module. Mainly used to define the relevant endpoints of services which are in charge of retrieving data from backend APIs. It's a 'OpaqueToken' and defined by 'IServiceConfig' interface. If **config** is not set, the default value will be used. ``` export const DefaultServiceConfig: IServiceConfig = { + systemInfoEndpoint: "/api/system", repositoryBaseEndpoint: "/api/repositories", logBaseEndpoint: "/api/logs", targetBaseEndpoint: "/api/targets", replicationRuleEndpoint: "/api/policies/replication", replicationJobEndpoint: "/api/jobs/replication", - langCookieKey: DEFAULT_LANG_COOKIE_KEY, - supportedLangs: DEFAULT_SUPPORTING_LANGS, - enablei18Support: false + enablei18Support: false, + defaultLang: DEFAULT_LANG, //'en-us' + langCookieKey: DEFAULT_LANG_COOKIE_KEY, //'harbor-lang' + supportedLangs: DEFAULT_SUPPORTING_LANGS,//['en-us','zh-cn','es-es'] + langMessageLoader: "local", + langMessagePathForHttpLoader: "i18n/langs/", + langMessageFileSuffixForHttpLoader: "-lang.json", + localI18nMessageVariableMap: {} }; ``` If you want to override the related items, declare your own 'IServiceConfig' interface and define the configuration value. E.g: Override 'repositoryBaseEndpoint' @@ -113,14 +125,52 @@ HarborLibraryModule.forRoot({ ``` It supports partially overriding. For the items not overridden, default values will be adopted. The items contained in **config** are: * **repositoryBaseEndpoint:** The base endpoint of the service used to handle the repositories of registry and/or tags of repository. Default value is "/api/repositories". + * **logBaseEndpoint:** The base endpoint of the service used to handle the recent access logs. Default is "/api/logs". + * **targetBaseEndpoint:** The base endpoint of the service used to handle the registry endpoints. Default is "/api/targets". + * **replicationRuleEndpoint:** The base endpoint of the service used to handle the replication rules. Default is "/api/policies/replication". + * **replicationJobEndpoint:** The base endpoint of the service used to handle the replication jobs. Default is "/api/jobs/replication". + * **langCookieKey:** The cookie key used to store the current used language preference. Default is "harbor-lang". + * **supportedLangs:** Declare what languages are supported. Default is ['en-us', 'zh-cn', 'es-es']. + * **enablei18Support:** To determine whether or not to enable the i18 multiple languages supporting. Default is false. +* **langMessageLoader:** To determine which loader will be used to load the required lang messages. Support two loaders: One is **'http'**, use async http to load json files with the specified url/path. Another is **'local'**, use local json variable to store the lang message. + +* **langMessagePathForHttpLoader:** Define the basic url/path prefix for the loader to find the json files if the 'langMessageLoader' is set to **'http'**. E.g: 'src/i18n/langs'. + +* **langMessageFileSuffixForHttpLoader:** Define the suffix of the json file names without lang name if 'langMessageLoader' is set to **'http'**. For example, '-lang.json' is suffix of message file 'en-us-lang.json'. + +* **localI18nMessageVariableMap:** If configuration property 'langMessageLoader' is set to **'local'** to load the i18n messages, this property must be defined to tell local JSON loader where to get the related messages. E.g: If declare the following messages storage variables, +``` + export const EN_US_LANG: any = { + "APP_TITLE": { + "VMW_HARBOR": "VMware Harbor", + "HARBOR": "Harbor" + } + } + + export const ZH_CN_LANG: any = { + "APP_TITLE": { + "VMW_HARBOR": "VMware Harbor中文版", + "HARBOR": "Harbor" + } + } +``` + +then this property should be set to: +``` + { + "en-us": EN_US_LANG, + "zh-cn": ZH_CN_LANG + }; +``` + **2. errorHandler** UI components in the library use this interface to pass the errors/warnings/infos/logs to the top component or page. The top component or page can display those information in their message panel or notification system. If not set, the console will be used as default output approach. diff --git a/src/ui_ng/lib/package.json b/src/ui_ng/lib/package.json index f3fed7588..95c81c95a 100644 --- a/src/ui_ng/lib/package.json +++ b/src/ui_ng/lib/package.json @@ -10,7 +10,7 @@ "pree2e": "webdriver-manager update", "e2e": "protractor", "cleanup": "rimraf dist", - "copy": "copyfiles -f LICENSE AUTHORS pkg/package.json dist", + "copy": "copyfiles -f README.md LICENSE AUTHORS pkg/package.json dist", "transpile": "ngc -p tsconfig.json", "package": "rollup -c", "minify": "uglifyjs dist/bundles/harborui.umd.js --screw-ie8 --compress --mangle --comments --output dist/bundles/harborui.umd.min.js", diff --git a/src/ui_ng/lib/pkg/package.json b/src/ui_ng/lib/pkg/package.json index 421658ca7..ca5cab297 100644 --- a/src/ui_ng/lib/pkg/package.json +++ b/src/ui_ng/lib/pkg/package.json @@ -1,6 +1,6 @@ { "name": "harbor-ui", - "version": "0.1.1", + "version": "0.1.24", "description": "Harbor shared UI components based on Clarity and Angular4", "author": "Harbor", "module": "index.js", diff --git a/src/ui_ng/lib/src/harbor-library.module.ts b/src/ui_ng/lib/src/harbor-library.module.ts index af21a2aa4..ff7b485ae 100644 --- a/src/ui_ng/lib/src/harbor-library.module.ts +++ b/src/ui_ng/lib/src/harbor-library.module.ts @@ -39,9 +39,10 @@ import { DefaultErrorHandler } from './error-handler/index'; import { SharedModule } from './shared/shared.module'; +import { TranslateModule } from '@ngx-translate/core'; + +import { TranslateServiceInitializer } from './i18n/index'; import { DEFAULT_LANG_COOKIE_KEY, DEFAULT_SUPPORTING_LANGS, DEFAULT_LANG } from './utils'; -import { TranslateService } from '@ngx-translate/core'; -import { CookieService } from 'ngx-cookie'; /** * Declare default service configuration; all the endpoints will be defined in @@ -54,9 +55,14 @@ export const DefaultServiceConfig: IServiceConfig = { targetBaseEndpoint: "/api/targets", replicationRuleEndpoint: "/api/policies/replication", replicationJobEndpoint: "/api/jobs/replication", + enablei18Support: false, + defaultLang: DEFAULT_LANG, langCookieKey: DEFAULT_LANG_COOKIE_KEY, supportedLangs: DEFAULT_SUPPORTING_LANGS, - enablei18Support: false + langMessageLoader: "local", + langMessagePathForHttpLoader: "i18n/langs/", + langMessageFileSuffixForHttpLoader: "-lang.json", + localI18nMessageVariableMap: {} }; /** @@ -98,31 +104,15 @@ export interface HarborModuleConfig { * @param {AppConfigService} configService * @returns */ -export function initConfig(translateService: TranslateService, config: IServiceConfig, cookie: CookieService) { +export function initConfig(translateInitializer: TranslateServiceInitializer, config: IServiceConfig) { return (init); function init() { - let selectedLang: string = DEFAULT_LANG; - - translateService.addLangs(config.supportedLangs ? config.supportedLangs : [DEFAULT_LANG]); - translateService.setDefaultLang(DEFAULT_LANG); - - if (config.enablei18Support) { - //If user has selected lang, then directly use it - let langSetting: string = cookie.get(config.langCookieKey ? config.langCookieKey : DEFAULT_LANG_COOKIE_KEY); - if (!langSetting || langSetting.trim() === "") { - //Use browser lang - langSetting = translateService.getBrowserCultureLang().toLowerCase(); - } - - if (config.supportedLangs && config.supportedLangs.length > 0) { - if (config.supportedLangs.find(lang => lang === langSetting)) { - selectedLang = langSetting; - } - } - } - - translateService.use(selectedLang); - console.log('initConfig => ', translateService.currentLang); + translateInitializer.init({ + enablei18Support: config.enablei18Support, + supportedLangs: config.supportedLangs, + defaultLang: config.defaultLang, + langCookieKey: config.langCookieKey + }); }; } @@ -160,7 +150,8 @@ export function initConfig(translateService: TranslateService, config: IServiceC LIST_REPLICATION_RULE_DIRECTIVES, CREATE_EDIT_RULE_DIRECTIVES, DATETIME_PICKER_DIRECTIVES, - VULNERABILITY_DIRECTIVES + VULNERABILITY_DIRECTIVES, + TranslateModule ], providers: [] }) @@ -179,13 +170,13 @@ export class HarborLibraryModule { config.tagService || { provide: TagService, useClass: TagDefaultService }, config.scanningService || { provide: ScanningResultService, useClass: ScanningResultDefaultService }, //Do initializing - TranslateService, + TranslateServiceInitializer, { provide: APP_INITIALIZER, useFactory: initConfig, - deps: [TranslateService, SERVICE_CONFIG], + deps: [TranslateServiceInitializer, SERVICE_CONFIG], multi: true - }, + } ] }; } diff --git a/src/ui_ng/lib/src/i18n/i18n-config.ts b/src/ui_ng/lib/src/i18n/i18n-config.ts new file mode 100644 index 000000000..decfd79da --- /dev/null +++ b/src/ui_ng/lib/src/i18n/i18n-config.ts @@ -0,0 +1,33 @@ +export interface i18nConfig { + /** + * The cookie key used to store the current used language preference. + * + * @type {string} + * @memberOf IServiceConfig + */ + langCookieKey?: string, + + /** + * Declare what languages are supported. + * + * @type {string[]} + * @memberOf IServiceConfig + */ + supportedLangs?: string[], + + /** + * Define the default language the translate service uses. + * + * @type {string} + * @memberOf i18nConfig + */ + defaultLang?: string; + + /** + * To determine whether or not to enable the i18 multiple languages supporting. + * + * @type {boolean} + * @memberOf IServiceConfig + */ + enablei18Support?: boolean; +} \ No newline at end of file diff --git a/src/ui_ng/lib/src/i18n/index.ts b/src/ui_ng/lib/src/i18n/index.ts new file mode 100644 index 000000000..7dd269acf --- /dev/null +++ b/src/ui_ng/lib/src/i18n/index.ts @@ -0,0 +1,2 @@ +export * from './translate-init.service'; +export * from './i18n-config'; \ No newline at end of file diff --git a/src/ui_ng/lib/src/i18n/lang/en-us-lang.ts b/src/ui_ng/lib/src/i18n/lang/en-us-lang.ts deleted file mode 100644 index 9d8a8d81c..000000000 --- a/src/ui_ng/lib/src/i18n/lang/en-us-lang.ts +++ /dev/null @@ -1,478 +0,0 @@ -export const EN_US_LANG: any = { - "APP_TITLE": { - "VMW_HARBOR": "VMware Harbor", - "HARBOR": "Harbor", - "VIC": "vSphere Integrated Containers", - "MGMT": "Management", - "REG": "Registry" - }, - "SIGN_IN": { - "REMEMBER": "Remember me", - "INVALID_MSG": "Invalid user name or password.", - "FORGOT_PWD": "Forgot password", - "HEADER_LINK": "Sign In" - }, - "SIGN_UP": { - "TITLE": "Sign Up" - }, - "BUTTON": { - "CANCEL": "CANCEL", - "OK": "OK", - "DELETE": "DELETE", - "LOG_IN": "LOG IN", - "SIGN_UP_LINK": "Sign up for an account", - "SIGN_UP": "SIGN UP", - "CONFIRM": "CONFIRM", - "SEND": "SEND", - "SAVE": "SAVE", - "TEST_MAIL": "TEST MAIL SERVER", - "CLOSE": "CLOSE", - "TEST_LDAP": "TEST LDAP SERVER", - "MORE_INFO": "More info...", - "YES": "YES", - "NO": "NO", - "NEGATIVE": "NEGATIVE" - }, - "TOOLTIP": { - "EMAIL": "Email should be a valid email address like name@example.com.", - "USER_NAME": "Cannot contain special characters and maximum length should be 20 characters.", - "FULL_NAME": "Maximum length should be 20 characters.", - "COMMENT": "Length of comment should be less than 20 characters.", - "CURRENT_PWD": "Current password is required.", - "PASSWORD": "Password should be at least 8 characters with at least 1 uppercase, 1 lowercase and 1 number.", - "CONFIRM_PWD": "Passwords do not match.", - "SIGN_IN_USERNAME": "Username is required.", - "SIGN_IN_PWD": "Password is required.", - "SIGN_UP_MAIL": "Email is only used for resetting your password.", - "SIGN_UP_REAL_NAME": "First and last name", - "ITEM_REQUIRED": "Field is required.", - "NUMBER_REQUIRED": "Field is required and should be numbers.", - "PORT_REQUIRED": "Field is required and should be valid port number.", - "EMAIL_EXISTING": "Email address already exists.", - "USER_EXISTING": "Username is already in use." - }, - "PLACEHOLDER": { - "CURRENT_PWD": "Enter current password", - "NEW_PWD": "Enter new password", - "CONFIRM_PWD": "Confirm new password", - "USER_NAME": "Enter username", - "MAIL": "Enter email address", - "FULL_NAME": "Enter full name", - "SIGN_IN_NAME": "Username", - "SIGN_IN_PWD": "Password" - }, - "PROFILE": { - "TITLE": "User Profile", - "USER_NAME": "Username", - "EMAIL": "Email", - "FULL_NAME": "First and last name", - "COMMENT": "Comments", - "PASSWORD": "Password", - "SAVE_SUCCESS": "User profile saved successfully." - }, - "CHANGE_PWD": { - "TITLE": "Change Password", - "CURRENT_PWD": "Current Password", - "NEW_PWD": "New Password", - "CONFIRM_PWD": "Confirm Password", - "SAVE_SUCCESS": "User password changed successfully.", - "PASS_TIPS": "At least 8 characters with 1 uppercase, 1 lowercase and 1 number" - }, - "ACCOUNT_SETTINGS": { - "PROFILE": "User Profile", - "CHANGE_PWD": "Change Password", - "ABOUT": "About", - "LOGOUT": "Log Out", - "ROOT_CERT": "Download Root Cert" - }, - "GLOBAL_SEARCH": { - "PLACEHOLDER": "Search Harbor...", - "PLACEHOLDER_VIC": "Search Registry..." - }, - "SIDE_NAV": { - "DASHBOARD": "Dashboard", - "PROJECTS": "Projects", - "SYSTEM_MGMT": { - "NAME": "Administration", - "USER": "Users", - "REPLICATION": "Replication", - "CONFIG": "Configuration" - }, - "LOGS": "Logs" - }, - "USER": { - "ADD_ACTION": "USER", - "ENABLE_ADMIN_ACTION": "Set as Administrator", - "DISABLE_ADMIN_ACTION": "Revoke Administrator", - "DEL_ACTION": "Delete", - "FILTER_PLACEHOLDER": "Filter users", - "COLUMN_NAME": "Name", - "COLUMN_ADMIN": "Administrator", - "COLUMN_EMAIL": "Email", - "COLUMN_REG_NAME": "Registration time", - "IS_ADMIN": "Yes", - "IS_NOT_ADMIN": "No", - "ADD_USER_TITLE": "New User", - "SAVE_SUCCESS": "New user created successfully.", - "DELETION_TITLE": "Confirm user deletion", - "DELETION_SUMMARY": "Do you want to delete user {{param}}?", - "DELETE_SUCCESS": "User deleted successfully.", - "ITEMS": "item(s)" - }, - "PROJECT": { - "PROJECTS": "Projects", - "NAME": "Project Name", - "ROLE": "Role", - "PUBLIC_OR_PRIVATE": "Access Level", - "REPO_COUNT": "Repositories Count", - "CREATION_TIME": "Creation Time", - "PUBLIC": "Public", - "PRIVATE": "Private", - "MAKE": "Make", - "NEW_POLICY": "New Replication Rule", - "DELETE": "Delete", - "MY_PROJECTS": "All Projects", - "PUBLIC_PROJECTS": "Public Projects", - "PROJECT": "Project", - "NEW_PROJECT": "New Project", - "NAME_IS_REQUIRED": "Project name is required.", - "NAME_MINIMUM_LENGTH": "Project name is too short, it should be greater than 2 characters.", - "NAME_ALREADY_EXISTS": "Project name already exists.", - "NAME_IS_ILLEGAL": "Project name is invalid.", - "UNKNOWN_ERROR": "An unknown error occurred while creating the project.", - "ITEMS": "item(s)", - "DELETION_TITLE": "Confirm project deletion", - "DELETION_SUMMARY": "Do you want to delete project {{param}}?", - "FILTER_PLACEHOLDER": "Filter Projects", - "REPLICATION_RULE": "Replication Rule", - "CREATED_SUCCESS": "Created project successfully.", - "DELETED_SUCCESS": "Deleted project successfully.", - "TOGGLED_SUCCESS": "Toggled project successfully.", - "FAILED_TO_DELETE_PROJECT": "Project contains repositories or replication rules cannot be deleted.", - "INLINE_HELP_PUBLIC": "When a project is set to public, anyone has read permission to the repositories under this project, and the user does not need to run \"docker login\" before pulling images under this project." - }, - "PROJECT_DETAIL": { - "REPOSITORIES": "Repositories", - "REPLICATION": "Replication", - "USERS": "Members", - "LOGS": "Logs", - "PROJECTS": "Projects" - }, - "MEMBER": { - "NEW_MEMBER": "New Member", - "MEMBER": "Member", - "NAME": "Name", - "ROLE": "Role", - "SYS_ADMIN": "System Admin", - "PROJECT_ADMIN": "Project Admin", - "DEVELOPER": "Developer", - "GUEST": "Guest", - "DELETE": "Delete", - "ITEMS": "item(s)", - "ACTIONS": "Actions", - "USERNAME_IS_REQUIRED": "Username is required", - "USERNAME_DOES_NOT_EXISTS": "Username does not exist.", - "USERNAME_ALREADY_EXISTS": "Username already exists.", - "UNKNOWN_ERROR": "Unknown error occurred while adding member.", - "FILTER_PLACEHOLDER": "Filter Members", - "DELETION_TITLE": "Confirm project member deletion", - "DELETION_SUMMARY": "Do you want to delete project member {{param}}?", - "ADDED_SUCCESS": "Added member successfully.", - "DELETED_SUCCESS": "Deleted member successfully.", - "SWITCHED_SUCCESS": "Switched member role successfully." - }, - "AUDIT_LOG": { - "USERNAME": "Username", - "REPOSITORY_NAME": "Repository Name", - "TAGS": "Tags", - "OPERATION": "Operation", - "OPERATIONS": "Operations", - "TIMESTAMP": "Timestamp", - "ALL_OPERATIONS": "All Operations", - "PULL": "Pull", - "PUSH": "Push", - "CREATE": "Create", - "DELETE": "Delete", - "OTHERS": "Others", - "ADVANCED": "Advanced", - "SIMPLE": "Simple", - "ITEMS": "item(s)", - "FILTER_PLACEHOLDER": "Filter Logs", - "INVALID_DATE": "Invalid date." - }, - "REPLICATION": { - "REPLICATION_RULE": "Replication Rule", - "NEW_REPLICATION_RULE": "New Replication Rule", - "ENDPOINTS": "Endpoints", - "FILTER_POLICIES_PLACEHOLDER": "Filter Rules", - "FILTER_JOBS_PLACEHOLDER": "Filter Jobs", - "DELETION_TITLE": "Confirm Rule Deletion", - "DELETION_SUMMARY": "Do you want to delete rule {{param}}?", - "FILTER_TARGETS_PLACEHOLDER": "Filter Endpoints", - "DELETION_TITLE_TARGET": "Confirm Endpoint Deletion", - "DELETION_SUMMARY_TARGET": "Do you want to delete the endpoint {{param}}?", - "ADD_POLICY": "New Replication Rule", - "EDIT_POLICY": "Edit", - "EDIT_POLICY_TITLE": "Edit Replication Rule", - "DELETE_POLICY": "Delete", - "TEST_CONNECTION": "Test Connection", - "TESTING_CONNECTION": "Testing Connection...", - "TEST_CONNECTION_SUCCESS": "Connection tested successfully.", - "TEST_CONNECTION_FAILURE": "Failed to ping endpoint.", - "NAME": "Name", - "PROJECT": "Project", - "NAME_IS_REQUIRED": "Name is required.", - "DESCRIPTION": "Description", - "ENABLE": "Enable", - "DISABLE": "Disable", - "DESTINATION_NAME": "Endpoint Name", - "DESTINATION_NAME_IS_REQUIRED": "Endpoint name is required.", - "NEW_DESTINATION": "New Endpoint", - "DESTINATION_URL": "Endpoint URL", - "DESTINATION_URL_IS_REQUIRED": "Endpoint URL is required.", - "DESTINATION_USERNAME": "Username", - "DESTINATION_PASSWORD": "Password", - "ALL_STATUS": "All Status", - "ENABLED": "Enabled", - "DISABLED": "Disabled", - "LAST_START_TIME": "Last Start Time", - "ACTIVATION": "Activation", - "REPLICATION_JOBS": "Replication Jobs", - "ALL": "All", - "PENDING": "Pending", - "RUNNING": "Running", - "ERROR": "Error", - "RETRYING": "Retrying", - "STOPPED": "Stopped", - "FINISHED": "Finished", - "CANCELED": "Canceled", - "SIMPLE": "Simple", - "ADVANCED": "Advanced", - "STATUS": "Status", - "OPERATION": "Operation", - "CREATION_TIME": "Start Time", - "END_TIME": "End Time", - "LOGS": "Logs", - "OF": "of", - "ITEMS": "item(s)", - "TOGGLE_ENABLE_TITLE": "Enable Rule", - "CONFIRM_TOGGLE_ENABLE_POLICY": "After enabling the replication rule, all repositories under the project will be replicated to the destination registry. \nPlease confirm to continue.", - "TOGGLE_DISABLE_TITLE": "Disable Rule", - "CONFIRM_TOGGLE_DISABLE_POLICY": "After disabling the rule, all unfinished replication jobs of this rule will be stopped and canceled. \nPlease confirm to continue.", - "CREATED_SUCCESS": "Created replication rule successfully.", - "UPDATED_SUCCESS": "Updated replication rule successfully.", - "DELETED_SUCCESS": "Deleted replication rule successfully.", - "DELETED_FAILED": "Deleted replication rule failed.", - "TOGGLED_SUCCESS": "Toggled replication rule status successfully.", - "CANNOT_EDIT": "Replication rule cannot be changed while it is enabled.", - "POLICY_ALREADY_EXISTS": "Replication rule already exists.", - "FAILED_TO_DELETE_POLICY_ENABLED": "Cannot delete rule: rule has unfinished job(s) or rule is enabled.", - "FOUND_ERROR_IN_JOBS": "Found errors in the replication job(s), please check.", - "INVALID_DATE": "Invalid date." - }, - "DESTINATION": { - "NEW_ENDPOINT": "New Endpoint", - "ENDPOINT": "Endpoint", - "NAME": "Endpoint Name", - "NAME_IS_REQUIRED": "Endpoint name is required.", - "URL": "Endpoint URL", - "URL_IS_REQUIRED": "Endpoint URL is required.", - "USERNAME": "Username", - "PASSWORD": "Password", - "TEST_CONNECTION": "Test Connection", - "TITLE_EDIT": "Edit Endpoint", - "TITLE_ADD": "Create Endpoint", - "DELETE": "Delete Endpoint", - "TESTING_CONNECTION": "Testing Connection...", - "TEST_CONNECTION_SUCCESS": "Connection tested successfully.", - "TEST_CONNECTION_FAILURE": "Failed to ping endpoint.", - "CONFLICT_NAME": "Endpoint name or URL already exists.", - "INVALID_NAME": "Invalid endpoint name.", - "FAILED_TO_GET_TARGET": "Failed to get endpoint.", - "CREATION_TIME": "Creation Time", - "OF": "of", - "ITEMS": "item(s)", - "CREATED_SUCCESS": "Created endpoint successfully.", - "UPDATED_SUCCESS": "Updated endpoint successfully.", - "DELETED_SUCCESS": "Deleted endpoint successfully.", - "DELETED_FAILED": "Deleted endpoint failed.", - "CANNOT_EDIT": "Endpoint cannot be changed while the replication rule is enabled.", - "FAILED_TO_DELETE_TARGET_IN_USED": "Failed to delete the endpoint in use." - }, - "REPOSITORY": { - "COPY_DIGEST_ID": "Copy Digest ID", - "DELETE": "Delete", - "NAME": "Name", - "TAGS_COUNT": "Tags", - "PULL_COUNT": "Pulls", - "PULL_COMMAND": "Pull Command", - "MY_REPOSITORY": "My Repository", - "PUBLIC_REPOSITORY": "Public Repository", - "DELETION_TITLE_REPO": "Confirm Repository Deletion", - "DELETION_SUMMARY_REPO": "Do you want to delete repository {{param}}?", - "DELETION_TITLE_TAG": "Confirm Tag Deletion", - "DELETION_SUMMARY_TAG": "Do you want to delete tag {{param}}?", - "DELETION_TITLE_TAG_DENIED": "Signed tag cannot be deleted", - "DELETION_SUMMARY_TAG_DENIED": "The tag must be removed from the Notary before it can be deleted.\nDelete from Notary via this command:\n{{param}}", - "FILTER_FOR_REPOSITORIES": "Filter Repositories", - "TAG": "Tag", - "SIGNED": "Signed", - "AUTHOR": "Author", - "CREATED": "Creation Time", - "DOCKER_VERSION": "Docker Version", - "ARCHITECTURE": "Architecture", - "OS": "OS", - "SHOW_DETAILS": "Show Details", - "REPOSITORIES": "Repositories", - "OF": "of", - "ITEMS": "item(s)", - "POP_REPOS": "Popular Repositories", - "DELETED_REPO_SUCCESS": "Deleted repository successfully.", - "DELETED_TAG_SUCCESS": "Deleted tag successfully.", - "COPY": "Copy" - }, - "ALERT": { - "FORM_CHANGE_CONFIRMATION": "Some changes are not saved yet. Do you want to cancel?" - }, - "RESET_PWD": { - "TITLE": "Reset Password", - "CAPTION": "Enter your email to reset your password", - "EMAIL": "Email", - "SUCCESS": "Mail with password resetting link is successfully sent. You can close this dialog and check your mailbox.", - "CAPTION2": "Enter your new password", - "RESET_OK": "Password has been successfully reset. Click OK to login with new password." - }, - "RECENT_LOG": { - "SUB_TITLE": "Show", - "SUB_TITLE_SUFIX": "logs" - }, - "CONFIG": { - "TITLE": "Configuration", - "AUTH": "Authentication", - "REPLICATION": "Replication", - "EMAIL": "Email", - "SYSTEM": "System Settings", - "CONFIRM_TITLE": "Confirm to cancel", - "CONFIRM_SUMMARY": "Some changes have not been saved. Do you want to discard them?", - "SAVE_SUCCESS": "Configuration has been successfully saved.", - "MAIL_SERVER": "Email Server", - "MAIL_SERVER_PORT": "Email Server Port", - "MAIL_USERNAME": "Email Username", - "MAIL_PASSWORD": "Email Password", - "MAIL_FROM": "Email From", - "MAIL_SSL": "Email SSL", - "SSL_TOOLTIP": "Enable SSL for email server connection", - "VERIFY_REMOTE_CERT": "Verify Remote Cert", - "TOKEN_EXPIRATION": "Token Expiration (Minutes)", - "AUTH_MODE": "Auth Mode", - "PRO_CREATION_RESTRICTION": "Project Creation", - "SELF_REGISTRATION": "Allow Self-Registration", - "AUTH_MODE_DB": "Database", - "AUTH_MODE_LDAP": "LDAP", - "SCOPE_BASE": "Base", - "SCOPE_ONE_LEVEL": "OneLevel", - "SCOPE_SUBTREE": "Subtree", - "PRO_CREATION_EVERYONE": "Everyone", - "PRO_CREATION_ADMIN": "Admin Only", - "TOOLTIP": { - "SELF_REGISTRATION": "Enable sign up.", - "VERIFY_REMOTE_CERT": "Determine whether the image replication should verify the certificate of a remote Harbor registry. Uncheck this box when the remote registry uses a self-signed or untrusted certificate.", - "AUTH_MODE": "By default the authentication mode is database, i.e. the credentials are stored in a local database. Set it to LDAP if you want to verify a user's credential against an LDAP server.", - "LDAP_SEARCH_DN": "A user's DN who has the permission to search the LDAP/AD server. If your LDAP/AD server does not support anonymous search, you should configure this DN and ldap_search_pwd.", - "LDAP_BASE_DN": "The base DN from which to look up a user in LDAP/AD.", - "LDAP_UID": "The attribute used in a search to match a user. It could be uid, cn, email, sAMAccountName or other attributes depending on your LDAP/AD.", - "LDAP_SCOPE": "The scope to search for users", - "TOKEN_EXPIRATION": "The expiration time (in minutes) of a token created by the token service. Default is 30 minutes.", - "PRO_CREATION_RESTRICTION": "The flag to define what users have permission to create projects. By default, everyone can create a project. Set to 'Admin Only' so that only an administrator can create a project." - }, - "LDAP": { - "URL": "LDAP URL", - "SEARCH_DN": "LDAP Search DN", - "SEARCH_PWD": "LDAP Search Password", - "BASE_DN": "LDAP Base DN", - "FILTER": "LDAP Filter", - "UID": "LDAP UID", - "SCOPE": "LDAP Scope" - }, - "TEST_MAIL_SUCCESS": "Connection to mail server is verified.", - "TEST_LDAP_SUCCESS": "Connection to LDAP server is verified.", - "TEST_MAIL_FAILED": "Failed to verify mail server with error: {{param}}.", - "TEST_LDAP_FAILED": "Failed to verify LDAP server with error: {{param}}.", - "LEAVING_CONFIRMATION_TITLE": "Confirm to leave", - "LEAVING_CONFIRMATION_SUMMARY": "Changes have not been saved yet. Do you want to leave current page?" - }, - "PAGE_NOT_FOUND": { - "MAIN_TITLE": "Page not found", - "SUB_TITLE": "Redirecting to main page in", - "UNIT": "seconds..." - }, - "ABOUT": { - "VERSION": "Version", - "BUILD": "Build", - "COPYRIGHT": "Copyright 1998-2017 VMware, Inc. All rights reserved. This product is protected by U.S. and international property laws. VMware products are covered by one or more patents listed at", - "COPYRIGHT_SUFIX": ".", - "TRADEMARK": "VMware is a registered trademark or trademark of VMware, Inc. in the United States and other jurisdictions. All other marks and names mentioned herein may be trademark of their respective companies.", - "END_USER_LICENSE": "End User License Agreement", - "OPEN_SOURCE_LICENSE": "Open Source/Third Party License" - }, - "START_PAGE": { - "GETTING_START": "", - "GETTING_START_TITLE": "Getting Started" - }, - "TOP_REPO": "Popular Repositories", - "STATISTICS": { - "TITLE": "STATISTICS", - "PRO_ITEM": "PROJECTS", - "REPO_ITEM": "REPOSITORIES", - "INDEX_MY": "MY", - "INDEX_MY_PROJECTS": "MY PROJECTS", - "INDEX_MY_REPOSITORIES": "MY REPOSITORIES", - "INDEX_PUB": "PUBLIC", - "INDEX_TOTAL": "TOTAL", - "STORAGE": "STORAGE", - "LIMIT": "Limit" - }, - "SEARCH": { - "IN_PROGRESS": "Search...", - "BACK": "Back" - }, - "VULNERABILITY": { - "STATE": { - "PENDING": "SCAN NOW", - "QUEUED": "Queued", - "ERROR": "Error", - "SCANNING": "Scanning", - "UNKNOWN": "Unknown" - }, - "GRID": { - "PLACEHOLDER": "We couldn't find any scanning results!", - "COLUMN_ID": "Vulnerability", - "COLUMN_SEVERITY": "Severity", - "COLUMN_PACKAGE": "Package", - "COLUMN_VERSION": "Current version", - "COLUMN_FIXED": "Fixed in version", - "COLUMN_LAYER": "Introduced in layer", - "FOOT_ITEMS": "Items", - "FOOT_OF": "of" - }, - "CHART": { - "SCANNING_TIME": "Scan completed", - "SEVERITY_HIGH": "High severity", - "SEVERITY_MEDIUM": "Medium severity", - "SEVERITY_LOW": "Low severity", - "SEVERITY_UNKNOWN": "Unknown", - "SEVERITY_NONE": "No Vulnerabilities" - }, - }, - "UNKNOWN_ERROR": "Unknown errors have occurred. Please try again later.", - "UNAUTHORIZED_ERROR": "Your session is invalid or has expired. You need to sign in to continue your action.", - "FORBIDDEN_ERROR": "You do not have the proper privileges to perform the action.", - "GENERAL_ERROR": "Errors have occurred when performing service call: {{param}}.", - "BAD_REQUEST_ERROR": "We are unable to perform your action because of a bad request.", - "NOT_FOUND_ERROR": "Your request cannot be completed because the object does not exist.", - "CONFLICT_ERROR": "We are unable to perform your action because your submission has conflicts.", - "PRECONDITION_FAILED": "We are unable to perform your action because of a precondition failure.", - "SERVER_ERROR": "We are unable to perform your action because internal server errors have occurred.", - "INCONRRECT_OLD_PWD": "The old password is incorrect.", - "UNKNOWN": "n/a" -}; \ No newline at end of file diff --git a/src/ui_ng/lib/src/i18n/lang/es-es-lang.ts b/src/ui_ng/lib/src/i18n/lang/es-es-lang.ts deleted file mode 100644 index c77c4a6b0..000000000 --- a/src/ui_ng/lib/src/i18n/lang/es-es-lang.ts +++ /dev/null @@ -1,475 +0,0 @@ -export const ES_ES_LANG: any = { - "APP_TITLE": { - "VMW_HARBOR": "VMware Harbor", - "HARBOR": "Harbor", - "VIC": "Contenedores Integrados vSphere", - "MGMT": "Administración", - "REG": "Registro" - }, - "SIGN_IN": { - "REMEMBER": "Recordarme", - "INVALID_MSG": "Nombre o contraseña no válidos.", - "FORGOT_PWD": "Olvidé mi contraseña", - "HEADER_LINK": "Identificarse" - }, - "SIGN_UP": { - "TITLE": "Registrarse" - }, - "BUTTON": { - "CANCEL": "CANCELAR", - "OK": "OK", - "DELETE": "ELIMINAR", - "LOG_IN": "IDENTIFICARSE", - "SIGN_UP_LINK": "Registrar una cuenta", - "SIGN_UP": "REGISTRARSE", - "CONFIRM": "CONFIRMAR", - "SEND": "ENVIAR", - "SAVE": "GUARDAR", - "TEST_MAIL": "COMPROBAR SERVIDOR DE CORREO", - "CLOSE": "CERRAR", - "TEST_LDAP": "COMPROBAR SERVIDOR LDAP", - "MORE_INFO": "Más información...", - "YES": "SI", - "NO": "NO", - "NEGATIVE": "NEGATIVO" - }, - "TOOLTIP": { - "EMAIL": "El email debe ser una dirección válida como nombre@ejemplo.com.", - "USER_NAME": "Debe tener una longitud máxima de 20 caracteres y no puede contener caracteres especiales.", - "FULL_NAME": "La longitud máxima debería ser de 20 caracteres.", - "COMMENT": "La longitud del comentario debería ser menor de 20 caracteres.", - "CURRENT_PWD": "Es obligatorio introducir la contraseña actual.", - "PASSWORD": "La contraseña debería tener al menos 8 caracteres, con al menos 1 letra mayúscula, 1 letra minúscula y 1 número.", - "CONFIRM_PWD": "Las contraseñas no coinciden.", - "SIGN_IN_USERNAME": "El nombre de usuario es obligatorio.", - "SIGN_IN_PWD": "La contraseña es obligatoria.", - "SIGN_UP_MAIL": "La dirección de email solamente se utilizar para restablecer la contraseña.", - "SIGN_UP_REAL_NAME": "Nombre y apellidos", - "ITEM_REQUIRED": "Campo obligatorio.", - "NUMBER_REQUIRED": "El campo es obligatorio y debería ser un número.", - "PORT_REQUIRED": "El campo es obligatorio y debería ser un número de puerto válido.", - "EMAIL_EXISTING": "Esa dirección de email ya existe.", - "USER_EXISTING": "Ese nombre de usuario ya existe." - }, - "PLACEHOLDER": { - "CURRENT_PWD": "Introduzca la contraseña actual", - "NEW_PWD": "Introduzca la nueva contraseña", - "CONFIRM_PWD": "Confirme la nueva contraseña", - "USER_NAME": "Introduzca nombre de usuario", - "MAIL": "Introduzca dirección de email", - "FULL_NAME": "Introduzca nombre completo", - "SIGN_IN_NAME": "Nombre de usuario", - "SIGN_IN_PWD": "Contraseña" - }, - "PROFILE": { - "TITLE": "Perfil de usuario", - "USER_NAME": "Nombre de usuario", - "EMAIL": "Email", - "FULL_NAME": "Nombre y apellidos", - "COMMENT": "Comentarios", - "PASSWORD": "Contraseña", - "SAVE_SUCCESS": "Perfil de usuario guardado satisfactoriamente." - }, - "CHANGE_PWD": { - "TITLE": "Cambiar contraseña", - "CURRENT_PWD": "Contraseña actual", - "NEW_PWD": "Nueva contraseña", - "CONFIRM_PWD": "Confirmar contraseña", - "SAVE_SUCCESS": "Contraseña de usuario guardada satisfactoriamente.", - "PASS_TIPS": "Al menos 8 caracteres con 1 letra mayúscula, 1 minúscula y 1 número" - }, - "ACCOUNT_SETTINGS": { - "PROFILE": "Perfil de usuario", - "CHANGE_PWD": "Cambiar contraseña", - "ABOUT": "Acerca de", - "LOGOUT": "Cerrar sesión", - "ROOT_CERT": "Descargar Certificado Raíz" - }, - "GLOBAL_SEARCH": { - "PLACEHOLDER": "Buscar en Harbor...", - "PLACEHOLDER_VIC": "Buscar en el registro..." - }, - "SIDE_NAV": { - "DASHBOARD": "Panel", - "PROJECTS": "Proyectos", - "SYSTEM_MGMT": { - "NAME": "Administración", - "USER": "Usuarios", - "REPLICATION": "Replicación", - "CONFIG": "Configuración" - }, - "LOGS": "Logs" - }, - "USER": { - "ADD_ACTION": "USUARIO", - "ENABLE_ADMIN_ACTION": "Marcar como Administrador", - "DISABLE_ADMIN_ACTION": "Desmarcar como Administrador", - "DEL_ACTION": "Eliminar", - "FILTER_PLACEHOLDER": "Filtrar usuarios", - "COLUMN_NAME": "Nombre", - "COLUMN_ADMIN": "Administrador", - "COLUMN_EMAIL": "Email", - "COLUMN_REG_NAME": "Fecha de registro", - "IS_ADMIN": "Si", - "IS_NOT_ADMIN": "No", - "ADD_USER_TITLE": "Nuevo usuario", - "SAVE_SUCCESS": "Nuevo usuario guardado satisfactoriamente.", - "DELETION_TITLE": "Confirmar eliminación de usuario", - "DELETION_SUMMARY": "¿Quiere eliminar el usuario {{param}}?", - "DELETE_SUCCESS": "Usuario eliminado satisfactoriamente.", - "ITEMS": "elemento(s)" - }, - "PROJECT": { - "PROJECTS": "Proyectos", - "NAME": "Nombre del Proyecto", - "ROLE": "Rol", - "PUBLIC_OR_PRIVATE": "Público", - "ACCESS_LEVEL": "Nivel de acceso", - "REPO_COUNT": "Contador de repositorios", - "CREATION_TIME": "Fecha de creación", - "PUBLIC": "Público", - "PRIVATE": "Privado", - "MAKE": "Hacer", - "NEW_POLICY": "Nueva regla de replicación", - "DELETE": "Eliminar", - "MY_PROJECTS": "Todos los proyectos", - "PUBLIC_PROJECTS": "Proyectos Públicos", - "PROJECT": "Proyecto", - "NEW_PROJECT": "Nuevo proyecto", - "NAME_IS_REQUIRED": "El nombre del proyecto es obligatorio.", - "NAME_MINIMUM_LENGTH": "El nombre del proyecto es demasiado corto, debe ser mayor de 2 caracteres.", - "NAME_ALREADY_EXISTS": "Ya existe un proyecto con ese nombre.", - "NAME_IS_ILLEGAL": "El nombre del proyecto no es valido.", - "UNKNOWN_ERROR": "Ha ocurrido un error al crear el proyecto.", - "ITEMS": "elemento(s)", - "DELETION_TITLE": "Confirmar eliminación del proyecto", - "DELETION_SUMMARY": "¿Quiere eliminar el proyecto {{param}}?", - "FILTER_PLACEHOLDER": "Filtrar proyectos", - "REPLICATION_RULE": "Reglas de replicación", - "CREATED_SUCCESS": "Proyecto creado satisfactoriamente.", - "DELETED_SUCCESS": "Proyecto eliminado satisfactoriamente.", - "TOGGLED_SUCCESS": "Proyecto alternado satisfactoriamente.", - "FAILED_TO_DELETE_PROJECT": "Los proyectos que contienen repositorios o reglas de replicación no pueden eliminarse.", - "INLINE_HELP_PUBLIC": "Cuando un proyecto se marca como público, todo el mundo tiene permisos de lectura sobre los repositorio de dicho proyecto, y no hace falta hacer \"docker login\" antes de subir imágenes a ellos." - }, - "PROJECT_DETAIL": { - "REPOSITORIES": "Repositorios", - "REPLICATION": "Replicación", - "USERS": "Miembros", - "LOGS": "Logs", - "PROJECTS": "Proyectos" - }, - "MEMBER": { - "NEW_MEMBER": "Nuevo miembro", - "MEMBER": "Miembro", - "NAME": "Nombre", - "ROLE": "Rol", - "SYS_ADMIN": "Administrador del sistema", - "PROJECT_ADMIN": "Administrador del proyecto", - "DEVELOPER": "Desarrollador", - "GUEST": "Invitado", - "DELETE": "Eliminar", - "ITEMS": "elemento(s)", - "ACTIONS": "Acciones", - "USERNAME_IS_REQUIRED": "El nombre de usuario es obligatorio", - "USERNAME_DOES_NOT_EXISTS": "Ese nombre de usuario no existe.", - "USERNAME_ALREADY_EXISTS": "Ese nombre de usuario ya existe.", - "UNKNOWN_ERROR": "Ha ocurrido un error al añadir el miembro.", - "FILTER_PLACEHOLDER": "Filtrar Miembros", - "DELETION_TITLE": "Confirmar eliminación de miembro de un proyecto", - "DELETION_SUMMARY": "¿Quiere eliminar el miembro {{param}} del proyecto?", - "ADDED_SUCCESS": "Miembro añadido satisfactoriamente.", - "DELETED_SUCCESS": "Miembro eliminado satisfactoriamente", - "SWITCHED_SUCCESS": "Rol del miembro cambiado satisfactoriamente." - }, - "AUDIT_LOG": { - "USERNAME": "Nombre de usuario", - "REPOSITORY_NAME": "Nombre del Repositorio", - "TAGS": "Etiquetas", - "OPERATION": "Operación", - "OPERATIONS": "Operaciones", - "TIMESTAMP": "Fecha", - "ALL_OPERATIONS": "Todas las operaciones", - "PULL": "Pull", - "PUSH": "Push", - "CREATE": "Crear", - "DELETE": "Eliminar", - "OTHERS": "Otros", - "ADVANCED": "Avanzado", - "SIMPLE": "Simple", - "ITEMS": "elemento(s)", - "FILTER_PLACEHOLDER": "Filtrar logs", - "INVALID_DATE": "Fecha invalida." - }, - "REPLICATION": { - "REPLICATION_RULE": "Reglas de Replicación", - "NEW_REPLICATION_RULE": "Nueva Regla de Replicación", - "ENDPOINTS": "Endpoints", - "FILTER_POLICIES_PLACEHOLDER": "Filtrar Reglas", - "FILTER_JOBS_PLACEHOLDER": "Filtrar Trabajos", - "DELETION_TITLE": "Confirmar Eliminación de Regla", - "DELETION_SUMMARY": "¿Quiere eliminar la regla {{param}}?", - "FILTER_TARGETS_PLACEHOLDER": "Filtrar Endpoints", - "DELETION_TITLE_TARGET": "Confirmar Eliminación de Endpoint", - "DELETION_SUMMARY_TARGET": "¿Quiere eliminar el endpoint {{param}}?", - "ADD_POLICY": "Nueva Regla de Replicación", - "EDIT_POLICY": "Editar", - "EDIT_POLICY_TITLE": "Editar Regla de Replicación", - "DELETE_POLICY": "Eliminar", - "TEST_CONNECTION": "Comprobar conexión", - "TESTING_CONNECTION": "Comprobando conexión...", - "TEST_CONNECTION_SUCCESS": "Conexión comprobada satisfactoriamente.", - "TEST_CONNECTION_FAILURE": "Fallo al conectar con el endpoint.", - "NAME": "Nombre", - "PROJECT": "Proyecto", - "NAME_IS_REQUIRED": "El nombre es obligatorio.", - "DESCRIPTION": "Descripción", - "ENABLE": "Activar", - "DISABLE": "Desactivar", - "DESTINATION_NAME": "Nombre del Endpoint", - "DESTINATION_NAME_IS_REQUIRED": "El nombre del endpoint es obligatorio.", - "NEW_DESTINATION": "Nuevo Endpoint", - "DESTINATION_URL": "URL del Endpoint", - "DESTINATION_URL_IS_REQUIRED": "La URL del endpoint es obligatoria.", - "DESTINATION_USERNAME": "Nombre de usuario", - "DESTINATION_PASSWORD": "Contraseña", - "ALL_STATUS": "Todos los estados", - "ENABLED": "Activado", - "DISABLED": "Desactivado", - "LAST_START_TIME": "Última Fecha de Inicio", - "ACTIVATION": "Activación", - "REPLICATION_JOBS": "Trabajos de Replicación", - "ALL": "Todos", - "PENDING": "Pendiente", - "RUNNING": "Ejecutando", - "ERROR": "Error", - "RETRYING": "Reintentando", - "STOPPED": "Parado", - "FINISHED": "Terminado", - "CANCELED": "Cancelado", - "SIMPLE": "Simple", - "ADVANCED": "Avanzado", - "STATUS": "Estado", - "OPERATION": "Operación", - "CREATION_TIME": "Fecha de Inicio", - "END_TIME": "Fecha de Finalización", - "LOGS": "Logs", - "ITEMS": "elemento(s)", - "TOGGLE_ENABLE_TITLE": "Activar Regla", - "CONFIRM_TOGGLE_ENABLE_POLICY": "Después de la activación de esta regla, todos los repositorios de este proyecto serán replicados al registro de destino.\nPor favor, confirme para continuar.", - "TOGGLE_DISABLE_TITLE": "Desactivar Regla", - "CONFIRM_TOGGLE_DISABLE_POLICY": "Después de la desactivación de la regla, todos los trabajos de replicación no finalizados serán interrumpidos y cancelados.\nPor favor, confirme para continuar.", - "CREATED_SUCCESS": "Regla de replicación creada satisfactoriamente.", - "UPDATED_SUCCESS": "Regla de replicación actualizada satisfactoriamente.", - "DELETED_SUCCESS": "Regla de replicación eliminada satisfactoriamente.", - "DELETED_FAILED": "Fallo al eliminar la regla de replicación.", - "TOGGLED_SUCCESS": "Regla de replicación cambiada satisfactoriamente.", - "CANNOT_EDIT": "La regla de replicación no se puede cambiar mientras esté activa.", - "POLICY_ALREADY_EXISTS": "La regla de replicación ya existe.", - "FAILED_TO_DELETE_POLICY_ENABLED": "No se puede eliminar la regla: tiene trabajo(s) sin finalizar o está activa.", - "FOUND_ERROR_IN_JOBS": "Se han encontrado errores en el trabajo de replicación. Por favor, compruébelos.", - "INVALID_DATE": "Fecha invalida." - }, - "DESTINATION": { - "NEW_ENDPOINT": "Nuevo Endpoint", - "ENDPOINT": "Endpoint", - "NAME": "Nombre del Endpoint", - "NAME_IS_REQUIRED": "El nombre del endpoint es obligatorio.", - "URL": "URL del Endpoint", - "URL_IS_REQUIRED": "La URL del endpoint es obligatoria.", - "USERNAME": "Nombre de usuario", - "PASSWORD": "Contraseña", - "TEST_CONNECTION": "Comprobar conexión", - "TITLE_EDIT": "Editar Endpoint", - "TITLE_ADD": "Crear Endpoint", - "DELETE": "Eliminar Endpoint", - "TESTING_CONNECTION": "Comprobar conexión...", - "TEST_CONNECTION_SUCCESS": "Conexión comprobada satisfactoriamente.", - "TEST_CONNECTION_FAILURE": "Fallo al comprobar el endpoint.", - "CONFLICT_NAME": "El nombre del endpoint ya existe.", - "INVALID_NAME": "El nombre del endpoint no es válido.", - "FAILED_TO_GET_TARGET": "Fallo al obtener el endpoint.", - "CREATION_TIME": "Fecha de creación", - "ITEMS": "elemento(s)", - "CREATED_SUCCESS": "Endpoint creado satisfactoriamente.", - "UPDATED_SUCCESS": "Endpoint actualizado satisfactoriamente.", - "DELETED_SUCCESS": "Endpoint eliminado satisfactoriamente.", - "DELETED_FAILED": "Ha fallado la eliminación del endpoint.", - "CANNOT_EDIT": "El endpoint no puede ser cambiado mientras la regla de replicación está activa.", - "FAILED_TO_DELETE_TARGET_IN_USED": "Fallo al eliminar el endpoint en uso." - }, - "REPOSITORY": { - "COPY_ID": "Copiar ID", - "COPY_PARENT_ID": "Copiar ID padre", - "DELETE": "Eliminar", - "NAME": "Nombre", - "TAGS_COUNT": "Etiquetas", - "PULL_COUNT": "Pulls", - "PULL_COMMAND": "Comando Pull", - "MY_REPOSITORY": "Mi Repositorio", - "PUBLIC_REPOSITORY": "Repositorio Público", - "DELETION_TITLE_REPO": "Confirmar Eliminación de Repositorio", - "DELETION_SUMMARY_REPO": "¿Quiere eliminar el repositorio {{param}}?", - "DELETION_TITLE_TAG": "Confirmación de Eliminación de Etiqueta", - "DELETION_SUMMARY_TAG": "¿Quiere eliminar la etiqueta {{param}}?", - "DELETION_TITLE_TAG_DENIED": "La etiqueta firmada no puede ser eliminada", - "DELETION_SUMMARY_TAG_DENIED": "La etiqueta debe ser eliminada de la Notaría antes de eliminarla.\nEliminarla de la Notaría con este comando:\n{{param}}", - "FILTER_FOR_REPOSITORIES": "Filtrar Repositorios", - "TAG": "Etiqueta", - "SIGNED": "Firmada", - "AUTHOR": "Autor", - "CREATED": "Fecha de creación", - "DOCKER_VERSION": "Version de Docker", - "ARCHITECTURE": "Arquitectura", - "OS": "SO", - "SHOW_DETAILS": "Mostrar Detalles", - "REPOSITORIES": "Repositorios", - "ITEMS": "elemento(s)", - "POP_REPOS": "Repositorios Populares", - "DELETED_REPO_SUCCESS": "Repositorio eliminado satisfactoriamente.", - "DELETED_TAG_SUCCESS": "Etiqueta eliminada satisfactoriamente.", - "COPY": "Copiar" - }, - "ALERT": { - "FORM_CHANGE_CONFIRMATION": "Algunos cambios no se han guardado aún. ¿Quiere cancelar?" - }, - "RESET_PWD": { - "TITLE": "Reiniciar Contraseña", - "CAPTION": "Introduzca el email para reiniciar la contraseña", - "EMAIL": "Email", - "SUCCESS": "El email con el enlace para restablecer la contraseña ha sido enviado satisfactoriamente. Puedes cerrar éste diálogo y comprobar tu bandeja de entrada de emails.", - "CAPTION2": "Introduce tu nueva contraseña", - "RESET_OK": "La contraseña ha sido reiniciada satisfactoriamente. Haz click en OK para identificarte con la nueva contraseña." - }, - "RECENT_LOG": { - "SUB_TITLE": "Mostrar", - "SUB_TITLE_SUFIX": "logs" - }, - "CONFIG": { - "TITLE": "Configuración", - "AUTH": "Autentificación", - "REPLICATION": "Replicación", - "EMAIL": "Email", - "SYSTEM": "Opciones del Sistema", - "CONFIRM_TITLE": "Confirma cancelación", - "CONFIRM_SUMMARY": "Algunos cambios no han sido guardados aún. ¿Quiere descartarlos?", - "SAVE_SUCCESS": "La configuración ha sido guardada satisfactoriamente.", - "MAIL_SERVER": "Servidor de email", - "MAIL_SERVER_PORT": "Puerto del servidor de email", - "MAIL_USERNAME": "Usuario del servidor de email", - "MAIL_PASSWORD": "Contraseña del servidor de email", - "MAIL_FROM": "Email De", - "MAIL_SSL": "Email SSL", - "SSL_TOOLTIP": "Activar SSL en conexiones al servidor de correo", - "VERIFY_REMOTE_CERT": "Verificar Certificado Remoto", - "TOKEN_EXPIRATION": "Expiración del Token (Minutos)", - "AUTH_MODE": "Modo de autentificación", - "PRO_CREATION_RESTRICTION": "Creación de Proyecto", - "SELF_REGISTRATION": "Permitir auto-registro", - "AUTH_MODE_DB": "Base de datos", - "AUTH_MODE_LDAP": "LDAP", - "SCOPE_BASE": "Base", - "SCOPE_ONE_LEVEL": "UnNivel", - "SCOPE_SUBTREE": "Subárbol", - "PRO_CREATION_EVERYONE": "Todos", - "PRO_CREATION_ADMIN": "Solo Administradores", - "TOOLTIP": { - "SELF_REGISTRATION": "Activar registro.", - "VERIFY_REMOTE_CERT": "Determina si la replicación de la imagen debería verificar el certificado de un registro Harbor remoto. Desmarque esta opción cuando el registro remoto use un certificado de confianza o autofirmado.", - "AUTH_MODE": "Por defecto el modo de autentificación es base de datos, es decir, las credenciales se almacenan en una base de datos local. Seleccione LDAP si quiere verificar las credenciales de usuarios a través del servidor LDAP.", - "LDAP_SEARCH_DN": "Un DN de usuario que tenga permisos para buscar el servidor LDAP/AD. Si el servidor LDAP/AD no soporta búsquedas anónimas, debería configurar este DN y ldap_search_pwd.", - "LDAP_BASE_DN": "La base DN para buscar un usuario en el LDAP/AD.", - "LDAP_UID": "El atributo usado en una búsqueda para encontrar un usuario. Debe ser el uid, cn, email, sAMAccountName u otro atributo dependiendo del LDAP/AD.", - "LDAP_SCOPE": "El ámbito de búsqueda para usuarios", - "TOKEN_EXPIRATION": "El tiempo de expiración (en minutos) del token creado por el servicio de tokens. Por defecto son 30 minutos.", - "PRO_CREATION_RESTRICTION": "Marca para definir qué usuarios tienen permisos para crear proyectos. Por defecto, todos pueden crear proyectos. Seleccione 'Solo Administradores' para que solamente los administradores puedan crear proyectos." - }, - "LDAP": { - "URL": "LDAP URL", - "SEARCH_DN": "LDAP Buscar DN", - "SEARCH_PWD": "LDAP Buscar Contraseña", - "BASE_DN": "LDAP Base DN", - "FILTER": "LDAP Filtro", - "UID": "LDAP UID", - "SCOPE": "LDAP Ámbito" - }, - "TEST_MAIL_SUCCESS": "La conexión al servidor de correo ha sido verificada.", - "TEST_LDAP_SUCCESS": "La conexión al servidor LDAP ha sido verificada.", - "TEST_MAIL_FAILED": "Fallo al verificar el servidor de correo con el error: {{param}}.", - "TEST_LDAP_FAILED": "Fallo al verificar el servidor LDAP con el error: {{param}}.", - "LEAVING_CONFIRMATION_TITLE": "Confirme la salida", - "LEAVING_CONFIRMATION_SUMMARY": "Los cambios no han sido guardados aún. ¿Quiere abandonar la página actual?" - }, - "PAGE_NOT_FOUND": { - "MAIN_TITLE": "Página no encontrada", - "SUB_TITLE": "Redirigiendo a la página principal en", - "UNIT": "segundos..." - }, - "ABOUT": { - "VERSION": "Versión", - "BUILD": "Construir", - "COPYRIGHT": "Copyright 1998-2017 VMware, Inc. Todos los derechos reservados. Este producto está protegido por E.U. y las leyes de propiedad internacionales. Los productos de VMware estan cubiertos por una o más patentes listadas en", - "COPYRIGHT_SUFIX": ".", - "TRADEMARK": "VMware es una marca registrada o marca de VMware, Inc. en los Estados Unidos y otras jurisdicciones. Todas las demás marcas y nombres mencionados son marcas de sus respectivas compañías.", - "END_USER_LICENSE": "Contrato de Usuario Final (EULA)", - "OPEN_SOURCE_LICENSE": "Código Abierto/Licencias de Terceros" - }, - "START_PAGE": { - "GETTING_START": "", - "GETTING_START_TITLE": "Comenzar" - }, - "TOP_REPO": "Repositorios Populares", - "STATISTICS": { - "TITLE": "ESTADÍSTICAS", - "PRO_ITEM": "PROYECTOS", - "REPO_ITEM": "REPOSITORIOS", - "INDEX_MY": "MI", - "INDEX_PUB": "PÚBLICO", - "INDEX_TOTAL": "TOTAL", - "STORAGE": "ALMACENAMIENTO", - "LIMIT": "Límite" - }, - "SEARCH": { - "IN_PROGRESS": "Buscar...", - "BACK": "Volver" - }, - "VULNERABILITY": { - "STATE": { - "PENDING": "SCAN NOW", - "QUEUED": "Queued", - "ERROR": "Error", - "SCANNING": "Scanning", - "UNKNOWN": "Unknown" - }, - "GRID": { - "PLACEHOLDER": "We couldn't find any scanning results!", - "COLUMN_ID": "Vulnerability", - "COLUMN_SEVERITY": "Severity", - "COLUMN_PACKAGE": "Package", - "COLUMN_VERSION": "Current version", - "COLUMN_FIXED": "Fixed in version", - "COLUMN_LAYER": "Introduced in layer", - "FOOT_ITEMS": "Items", - "FOOT_OF": "of" - }, - "CHART": { - "SCANNING_TIME": "Scan completed", - "SEVERITY_HIGH": "High severity", - "SEVERITY_MEDIUM": "Medium severity", - "SEVERITY_LOW": "Low severity", - "SEVERITY_UNKNOWN": "Unknown", - "SEVERITY_NONE": "No Vulnerabilities" - }, - }, - "UNKNOWN_ERROR": "Ha ocurrido un error desconocido. Por favor, inténtelo de nuevo más tarde.", - "UNAUTHORIZED_ERROR": "La sesión no es válida o ha caducado. Necesita identificarse de nuevo para llevar a cabo esa acción.", - "FORBIDDEN_ERROR": "No tienes permisos para llevar a cabo esa acción.", - "GENERAL_ERROR": "Han ocurrido errores cuando se llamaba al servicio: {{param}}.", - "BAD_REQUEST_ERROR": "No hemos podido llevar la acción debido a una solicitud incorrecta.", - "NOT_FOUND_ERROR": "La solicitud no puede ser completada porque el objeto no existe.", - "CONFLICT_ERROR": "No hemos podido llevar a cabo la acción debido a un conflicto.", - "PRECONDITION_FAILED": "No hemos podido llevar a cabo la acción debido a un error de precondición.", - "SERVER_ERROR": "No hemos podido llevar a cabo la acción debido a un error interno.", - "INCONRRECT_OLD_PWD": "La contraseña antigua no es correcta.", - "UNKNOWN": "n/a" -}; \ No newline at end of file diff --git a/src/ui_ng/lib/src/i18n/lang/zh-cn-lang.ts b/src/ui_ng/lib/src/i18n/lang/zh-cn-lang.ts deleted file mode 100644 index 87a95c0ad..000000000 --- a/src/ui_ng/lib/src/i18n/lang/zh-cn-lang.ts +++ /dev/null @@ -1,478 +0,0 @@ -export const ZH_CN_LANG: any = { - "APP_TITLE": { - "VMW_HARBOR": "VMware Harbor", - "HARBOR": "Harbor", - "VIC": "vSphere Integrated Containers", - "MGMT": "Management", - "REG": "Registry" - }, - "SIGN_IN": { - "REMEMBER": "记住我", - "INVALID_MSG": "用户名或者密码不正确。", - "FORGOT_PWD": "忘记密码", - "HEADER_LINK": "登录" - }, - "SIGN_UP": { - "TITLE": "注册" - }, - "BUTTON": { - "CANCEL": "取消", - "OK": "确定", - "DELETE": "删除", - "LOG_IN": "登录", - "SIGN_UP_LINK": "注册账号", - "SIGN_UP": "注册", - "CONFIRM": "确定", - "SEND": "发送", - "SAVE": "保存", - "TEST_MAIL": "测试邮件服务器", - "CLOSE": "关闭", - "TEST_LDAP": "测试LDAP服务器", - "MORE_INFO": "更多信息...", - "YES": "是", - "NO": "否", - "NEGATIVE": "否" - }, - "TOOLTIP": { - "EMAIL": "请使用正确的邮箱地址,比如name@example.com。", - "USER_NAME": "不能包含特殊字符且长度不能超过20。", - "FULL_NAME": "长度不能超过20。", - "COMMENT": "长度不能超过20。", - "CURRENT_PWD": "当前密码为必填项。", - "PASSWORD": "密码长度至少为8且需包含至少一个大写字符,一个小写字符和一个数字。", - "CONFIRM_PWD": "密码输入不一致。", - "SIGN_IN_USERNAME": "用户名为必填项。", - "SIGN_IN_PWD": "密码为必填项。", - "SIGN_UP_MAIL": "邮件地址仅用来重置您的密码。", - "SIGN_UP_REAL_NAME": "全名", - "ITEM_REQUIRED": "此项为必填项。", - "NUMBER_REQUIRED": "此项为必填项且为数字。", - "PORT_REQUIRED": "此项为必填项且为合法端口号。", - "EMAIL_EXISTING": "邮件地址已经存在。", - "USER_EXISTING": "用户名已经存在。" - }, - "PLACEHOLDER": { - "CURRENT_PWD": "输入当前密码", - "NEW_PWD": "输入新密码", - "CONFIRM_PWD": "确认新密码", - "USER_NAME": "输入用户名称", - "MAIL": "输入邮箱地址", - "FULL_NAME": "输入全名", - "SIGN_IN_NAME": "用户名", - "SIGN_IN_PWD": "密码" - }, - "PROFILE": { - "TITLE": "用户设置", - "USER_NAME": "用户名", - "EMAIL": "邮箱", - "FULL_NAME": "全名", - "COMMENT": "注释", - "PASSWORD": "密码", - "SAVE_SUCCESS": "成功保存用户设置。" - }, - "CHANGE_PWD": { - "TITLE": "修改密码", - "CURRENT_PWD": "当前密码", - "NEW_PWD": "新密码", - "CONFIRM_PWD": "确认密码", - "SAVE_SUCCESS": "成功更改用户密码。", - "PASS_TIPS": "至少8个字符且需包含至少一个大写字符、小写字符或者数字" - }, - "ACCOUNT_SETTINGS": { - "PROFILE": "用户设置", - "CHANGE_PWD": "修改密码", - "ABOUT": "关于", - "LOGOUT": "退出", - "ROOT_CERT": "下载根证书" - }, - "GLOBAL_SEARCH": { - "PLACEHOLDER": "搜索 Harbor...", - "PLACEHOLDER_VIC": "搜索 Registry..." - }, - "SIDE_NAV": { - "DASHBOARD": "仪表板", - "PROJECTS": "项目", - "SYSTEM_MGMT": { - "NAME": "系统管理", - "USER": "用户管理", - "REPLICATION": "复制管理", - "CONFIG": "配置管理" - }, - "LOGS": "日志" - }, - "USER": { - "ADD_ACTION": "用户", - "ENABLE_ADMIN_ACTION": "设置为管理员", - "DISABLE_ADMIN_ACTION": "取消管理员", - "DEL_ACTION": "删除", - "FILTER_PLACEHOLDER": "过滤用户", - "COLUMN_NAME": "用户名", - "COLUMN_ADMIN": "管理员", - "COLUMN_EMAIL": "邮件", - "COLUMN_REG_NAME": "注册时间", - "IS_ADMIN": "是", - "IS_NOT_ADMIN": "否", - "ADD_USER_TITLE": "创建用户", - "SAVE_SUCCESS": "成功创建用户。", - "DELETION_TITLE": "删除用户确认", - "DELETION_SUMMARY": "你确认删除用户 {{param}}?", - "DELETE_SUCCESS": "成功删除用户。", - "ITEMS": "条记录" - }, - "PROJECT": { - "PROJECTS": "项目", - "NAME": "项目名称", - "ROLE": "角色", - "PUBLIC_OR_PRIVATE": "访问级别", - "REPO_COUNT": "镜像仓库数", - "CREATION_TIME": "创建时间", - "PUBLIC": "公开", - "PRIVATE": "私有", - "MAKE": "设为", - "NEW_POLICY": "新建规则", - "DELETE": "删除", - "MY_PROJECTS": "所有项目", - "PUBLIC_PROJECTS": "公开项目", - "PROJECT": "项目", - "NEW_PROJECT": "新建项目", - "NAME_IS_REQUIRED": "项目名称为必填项", - "NAME_MINIMUM_LENGTH": "项目名称长度过短,至少多于2个字符。", - "NAME_ALREADY_EXISTS": "项目名称已存在。", - "NAME_IS_ILLEGAL": "项目名称非法。", - "UNKNOWN_ERROR": "创建项目时发生未知错误。", - "ITEMS": "条记录", - "DELETION_TITLE": "删除项目确认", - "DELETION_SUMMARY": "你确认删除项目 {{param}}?", - "FILTER_PLACEHOLDER": "过滤项目", - "REPLICATION_RULE": "复制规则", - "CREATED_SUCCESS": "成功创建项目。", - "DELETED_SUCCESS": "成功删除项目。", - "TOGGLED_SUCCESS": "切换状态成功。", - "FAILED_TO_DELETE_PROJECT": "项目包含镜像仓库或复制规则,无法删除。", - "INLINE_HELP_PUBLIC": "当项目设为公开后,任何人都有此项目下镜像的读权限。命令行用户不需要“docker login”就可以拉取此项目下的镜像。" - }, - "PROJECT_DETAIL": { - "REPOSITORIES": "镜像仓库", - "REPLICATION": "复制", - "USERS": "成员", - "LOGS": "日志", - "PROJECTS": "项目" - }, - "MEMBER": { - "NEW_MEMBER": "新建成员", - "MEMBER": "成员", - "NAME": "姓名", - "ROLE": "角色", - "SYS_ADMIN": "系统管理员", - "PROJECT_ADMIN": "项目管理员", - "DEVELOPER": "开发人员", - "GUEST": "访客", - "DELETE": "删除", - "ITEMS": "条记录", - "ACTIONS": "操作", - "USERNAME_IS_REQUIRED": "用户名为必填项。", - "USERNAME_DOES_NOT_EXISTS": "用户名不存在。", - "USERNAME_ALREADY_EXISTS": "用户名已存在。", - "UNKNOWN_ERROR": "添加成员时发生未知错误。", - "FILTER_PLACEHOLDER": "过滤成员", - "DELETION_TITLE": "删除项目成员确认", - "DELETION_SUMMARY": "你确认删除项目成员 {{param}}?", - "ADDED_SUCCESS": "成功新增成员。", - "DELETED_SUCCESS": "成功删除成员。", - "SWITCHED_SUCCESS": "切换角色成功。" - }, - "AUDIT_LOG": { - "USERNAME": "用户名", - "REPOSITORY_NAME": "镜像名称", - "TAGS": "标签", - "OPERATION": "操作", - "OPERATIONS": "操作", - "TIMESTAMP": "时间戳", - "ALL_OPERATIONS": "所有操作", - "PULL": "Pull", - "PUSH": "Push", - "CREATE": "Create", - "DELETE": "Delete", - "OTHERS": "其他", - "ADVANCED": "高级检索", - "SIMPLE": "简单检索", - "ITEMS": "条记录", - "FILTER_PLACEHOLDER": "过滤日志", - "INVALID_DATE": "无效日期。" - }, - "REPLICATION": { - "REPLICATION_RULE": "复制规则", - "NEW_REPLICATION_RULE": "新建规则", - "ENDPOINTS": "目标", - "FILTER_POLICIES_PLACEHOLDER": "过滤规则", - "FILTER_JOBS_PLACEHOLDER": "过滤任务", - "DELETION_TITLE": "删除规则确认", - "DELETION_SUMMARY": "确认删除规则 {{param}}?", - "FILTER_TARGETS_PLACEHOLDER": "过滤目标", - "DELETION_TITLE_TARGET": "删除目标确认", - "DELETION_SUMMARY_TARGET": "确认删除目标 {{param}}?", - "ADD_POLICY": "新建规则", - "EDIT_POLICY": "修改", - "EDIT_POLICY_TITLE": "修改规则", - "DELETE_POLICY": "删除", - "TEST_CONNECTION": "测试连接", - "TESTING_CONNECTION": "正在测试连接...", - "TEST_CONNECTION_SUCCESS": "测试连接成功。", - "TEST_CONNECTION_FAILURE": "测试连接失败。", - "NAME": "名称", - "PROJECT": "项目", - "NAME_IS_REQUIRED": "名称为必填项。", - "DESCRIPTION": "描述", - "ENABLE": "启用", - "DISABLE": "停用", - "DESTINATION_NAME": "目标名", - "DESTINATION_NAME_IS_REQUIRED": "目标名称为必填项。", - "NEW_DESTINATION": "创建目标", - "DESTINATION_URL": "目标URL", - "DESTINATION_URL_IS_REQUIRED": "目标URL为必填项。", - "DESTINATION_USERNAME": "用户名", - "DESTINATION_PASSWORD": "密码", - "ALL_STATUS": "所有状态", - "ENABLED": "启用", - "DISABLED": "停用", - "LAST_START_TIME": "上次起始时间", - "ACTIVATION": "活动状态", - "REPLICATION_JOBS": "复制任务", - "ALL": "全部", - "PENDING": "挂起", - "RUNNING": "运行中", - "ERROR": "错误", - "RETRYING": "重试中", - "STOPPED": "已停止", - "FINISHED": "已完成", - "CANCELED": "已取消", - "SIMPLE": "简单检索", - "ADVANCED": "高级检索", - "STATUS": "状态", - "OPERATION": "操作", - "CREATION_TIME": "创建时间", - "END_TIME": "结束时间", - "LOGS": "日志", - "OF": "共计", - "ITEMS": "条记录", - "TOGGLE_ENABLE_TITLE": "启用规则", - "CONFIRM_TOGGLE_ENABLE_POLICY": "启用规则后,该项目下的所有镜像仓库将复制到目标实例。\n请确认继续。", - "TOGGLE_DISABLE_TITLE": "停用规则", - "CONFIRM_TOGGLE_DISABLE_POLICY": "停用规则后,所有未完成的复制任务将被终止和取消。\n请确认继续。", - "CREATED_SUCCESS": "创建复制规则成功。", - "UPDATED_SUCCESS": "更新复制规则成功。", - "DELETED_SUCCESS": "删除复制规则成功。", - "DELETED_FAILED": "删除复制规则失败。", - "TOGGLED_SUCCESS": "切换复制规则状态成功。", - "CANNOT_EDIT": "当复制规则启用时无法修改。", - "POLICY_ALREADY_EXISTS": "规则已存在。", - "FAILED_TO_DELETE_POLICY_ENABLED": "删除复制规则失败: 仍有未完成的任务或规则未停用。", - "FOUND_ERROR_IN_JOBS": "复制任务中包含错误,请检查。", - "INVALID_DATE": "无效日期。" - }, - "DESTINATION": { - "NEW_ENDPOINT": "新建目标", - "ENDPOINT": "目标", - "NAME": "目标名", - "NAME_IS_REQUIRED": "目标名为必填项。", - "URL": "目标URL", - "URL_IS_REQUIRED": "目标URL为必填项。", - "USERNAME": "用户名", - "PASSWORD": "密码", - "TEST_CONNECTION": "测试连接", - "TITLE_EDIT": "编辑目标", - "TITLE_ADD": "新建目标", - "DELETE": "删除目标", - "TESTING_CONNECTION": "正在测试连接...", - "TEST_CONNECTION_SUCCESS": "测试连接成功。", - "TEST_CONNECTION_FAILURE": "测试连接失败。", - "CONFLICT_NAME": "目标名或目标URL已存在。", - "INVALID_NAME": "无效的目标名称。", - "FAILED_TO_GET_TARGET": "获取目标失败。", - "CREATION_TIME": "创建时间", - "OF": "共计", - "ITEMS": "条记录", - "CREATED_SUCCESS": "成功创建目标。", - "UPDATED_SUCCESS": "成功更新目标。", - "DELETED_SUCCESS": "成功删除目标。", - "DELETED_FAILED": "删除目标失败。", - "CANNOT_EDIT": "当复制规则启用时目标无法修改。", - "FAILED_TO_DELETE_TARGET_IN_USED": "无法删除正在使用的目标。" - }, - "REPOSITORY": { - "COPY_DIGEST_ID": "复制摘要ID", - "DELETE": "删除", - "NAME": "名称", - "TAGS_COUNT": "标签数", - "PULL_COUNT": "下载数", - "PULL_COMMAND": "Pull命令", - "MY_REPOSITORY": "我的仓库", - "PUBLIC_REPOSITORY": "公共仓库", - "DELETION_TITLE_REPO": "删除镜像仓库确认", - "DELETION_SUMMARY_REPO": "确认删除镜像仓库 {{param}}?", - "DELETION_TITLE_TAG": "删除镜像标签确认", - "DELETION_SUMMARY_TAG": "确认删除镜像标签 {{param}}?", - "DELETION_TITLE_TAG_DENIED": "已签名的镜像不能被删除", - "DELETION_SUMMARY_TAG_DENIED": "要删除此镜像标签必须首先从Notary中删除。\n请执行如下Notary命令删除:\n{{param}}", - "FILTER_FOR_REPOSITORIES": "过滤镜像仓库", - "TAG": "标签", - "SIGNED": "已签名", - "AUTHOR": "作者", - "CREATED": "创建时间", - "DOCKER_VERSION": "Docker版本", - "ARCHITECTURE": "架构", - "OS": "操作系统", - "SHOW_DETAILS": "显示详细", - "REPOSITORIES": "镜像仓库", - "OF": "共计", - "ITEMS": "条记录", - "POP_REPOS": "受欢迎的镜像仓库", - "DELETED_REPO_SUCCESS": "成功删除镜像仓库。", - "DELETED_TAG_SUCCESS": "成功删除镜像标签。", - "COPY": "复制" - }, - "ALERT": { - "FORM_CHANGE_CONFIRMATION": "表单内容改变,确认是否取消?" - }, - "RESET_PWD": { - "TITLE": "重置密码", - "CAPTION": "输入用来重置密码的邮箱", - "EMAIL": "邮箱", - "SUCCESS": "重置密码邮件已成功发送. 请关闭对话框并检查邮箱。", - "CAPTION2": "请输入您的新密码", - "RESET_OK": "密码重置成功,点击确定按钮重新登录。" - }, - "RECENT_LOG": { - "SUB_TITLE": "显示", - "SUB_TITLE_SUFIX": "条日志" - }, - "CONFIG": { - "TITLE": "配置", - "AUTH": "认证模式", - "REPLICATION": "复制", - "EMAIL": "邮箱", - "SYSTEM": "系统设置", - "CONFIRM_TITLE": "确认取消", - "CONFIRM_SUMMARY": "配置项有改动, 确定取消?", - "SAVE_SUCCESS": "变更的配置项成功保存。", - "MAIL_SERVER": "邮件服务器", - "MAIL_SERVER_PORT": "邮件服务器端口", - "MAIL_USERNAME": "用户名", - "MAIL_PASSWORD": "密码", - "MAIL_FROM": "邮件来源", - "MAIL_SSL": "邮件 SSL", - "SSL_TOOLTIP": "启用SSL到邮件服务器连接。", - "VERIFY_REMOTE_CERT": "验证远程证书", - "TOKEN_EXPIRATION": "令牌过期时间(分钟)", - "AUTH_MODE": "认证模式", - "PRO_CREATION_RESTRICTION": "项目创建", - "SELF_REGISTRATION": "允许自注册", - "AUTH_MODE_DB": "数据库", - "AUTH_MODE_LDAP": "LDAP", - "SCOPE_BASE": "本层", - "SCOPE_ONE_LEVEL": "下一层", - "SCOPE_SUBTREE": "子树", - "PRO_CREATION_EVERYONE": "所有人", - "PRO_CREATION_ADMIN": "仅管理员", - "TOOLTIP": { - "SELF_REGISTRATION": "激活注册功能。", - "VERIFY_REMOTE_CERT": "确定镜像复制是否要验证远程Harbor实例的证书。如果远程实例使用的是自签或者非信任证书,不要勾选此项。", - "AUTH_MODE": "默认认证模式为数据库认证,即用户凭证存储在本地数据库。如果使用LDAP来认证用户,则设置为LDAP。", - "LDAP_SEARCH_DN": "有搜索权限的LDAP用户DN。如果LDAP服务器不支持匿名搜索,则需要配置此DN及其密码。", - "LDAP_BASE_DN": "用来在LDAP和AD中搜寻用户的基础DN。", - "LDAP_UID": "在搜索中用来匹配用户的属性,可以是uid,cn,email,sAMAccountName或者其它LDAP/AD服务器支持的属性。", - "LDAP_SCOPE": "搜索用户的范围。", - "TOKEN_EXPIRATION": "由令牌服务创建的令牌的过期时间(分钟),默认为30分钟。", - "PRO_CREATION_RESTRICTION": "用来确定哪些用户有权限创建项目,默认为’所有人‘,设置为’仅管理员‘则只有管理员可以创建项目。" - }, - "LDAP": { - "URL": "LDAP URL", - "SEARCH_DN": "LDAP搜索DN", - "SEARCH_PWD": "LDAP搜索密码", - "BASE_DN": "LDAP基础DN", - "FILTER": "LDAP过滤器", - "UID": "LDAP用户UID的属性", - "SCOPE": "LDAP搜索范围" - }, - "TEST_MAIL_SUCCESS": "邮件服务器的连通正常。", - "TEST_LDAP_SUCCESS": "LDAP服务器的连通正常。", - "TEST_MAIL_FAILED": "验证邮件服务器失败,错误: {{param}}。", - "TEST_LDAP_FAILED": "验证LDAP服务器失败,错误: {{param}}。", - "LEAVING_CONFIRMATION_TITLE": "确定离开", - "LEAVING_CONFIRMATION_SUMMARY": "有未保存的配置更改, 确认离开当前页面?" - }, - "PAGE_NOT_FOUND": { - "MAIN_TITLE": "页面不存在", - "SUB_TITLE": "正在重定向到首页:", - "UNIT": "秒..." - }, - "ABOUT": { - "VERSION": "版本", - "BUILD": "构建", - "COPYRIGHT": "版权所有 © 1998-2017 VMware, Inc. 保留所有权利。此产品受美国及其他国家/地区的版权和知识产权以及国际条约保护。VMware产品受", - "COPYRIGHT_SUFIX": "上列出的一项或多项专利保护。", - "TRADEMARK": "VMware徽标及设计都是VMware, Inc.在美国和/或其他法律辖区的注册商标或者商标。此处提到的其他所有商标和名称分别是其各自公司的商标。", - "END_USER_LICENSE": "终端用户许可协议", - "OPEN_SOURCE_LICENSE": "开源/第三方许可协议" - }, - "START_PAGE": { - "GETTING_START": "", - "GETTING_START_TITLE": "从这开始" - }, - "TOP_REPO": "受欢迎的镜像仓库", - "STATISTICS": { - "TITLE": "统计", - "PRO_ITEM": "项目", - "REPO_ITEM": "镜像仓库", - "INDEX_MY": "私有", - "INDEX_MY_PROJECTS": "我的项目", - "INDEX_MY_REPOSITORIES": "我的镜像仓库", - "INDEX_PUB": "公开", - "INDEX_TOTAL": "总计", - "STORAGE": "存储", - "LIMIT": "容量" - }, - "SEARCH": { - "IN_PROGRESS": "搜索中...", - "BACK": "返回" - }, - "VULNERABILITY": { - "STATE": { - "PENDING": "开始扫描", - "QUEUED": "已入队列", - "ERROR": "错误", - "SCANNING": "扫描中", - "UNKNOWN": "未知" - }, - "GRID": { - "PLACEHOLDER": "没有扫描结果!", - "COLUMN_ID": "缺陷码", - "COLUMN_SEVERITY": "严重度", - "COLUMN_PACKAGE": "组件", - "COLUMN_VERSION": "当前版本", - "COLUMN_FIXED": "修复版本", - "COLUMN_LAYER": "引入层", - "FOOT_ITEMS": "项目", - "FOOT_OF": "总共" - }, - "CHART": { - "SCANNING_TIME": "扫描完成", - "SEVERITY_HIGH": "严重", - "SEVERITY_MEDIUM": "中等", - "SEVERITY_LOW": "低", - "SEVERITY_UNKNOWN": "未知", - "SEVERITY_NONE": "无缺陷" - }, - }, - "UNKNOWN_ERROR": "发生未知错误,请稍后再试。", - "UNAUTHORIZED_ERROR": "会话无效或者已经过期, 请重新登录以继续。", - "FORBIDDEN_ERROR": "当前操作被禁止,请确认你有合法的权限。", - "GENERAL_ERROR": "调用后台服务时出现错误: {{param}}。", - "BAD_REQUEST_ERROR": "错误请求, 操作无法完成。", - "NOT_FOUND_ERROR": "对象不存在, 请求无法完成。", - "CONFLICT_ERROR": "请求包含冲突, 操作无法完成。", - "PRECONDITION_FAILED": "验证前置条件失败, 无法执行操作。", - "SERVER_ERROR": "服务器出现内部错误,请求无法完成。", - "INCONRRECT_OLD_PWD": "旧密码不正确。", - "UNKNOWN": "未知" -}; \ No newline at end of file diff --git a/src/ui_ng/lib/src/i18n/local-json.loader.ts b/src/ui_ng/lib/src/i18n/local-json.loader.ts index cc2048af6..1157f46e1 100644 --- a/src/ui_ng/lib/src/i18n/local-json.loader.ts +++ b/src/ui_ng/lib/src/i18n/local-json.loader.ts @@ -1,20 +1,8 @@ import { TranslateLoader } from '@ngx-translate/core'; import 'rxjs/add/observable/of'; - import { Observable } from 'rxjs/Observable'; -import { EN_US_LANG } from './lang/en-us-lang'; -import { ES_ES_LANG } from './lang/es-es-lang'; -import { ZH_CN_LANG } from './lang/zh-cn-lang'; - -/** - * Define language mapping - */ -export const langs: { [key: string]: any } = { - "en-us": EN_US_LANG, - "es-es": ES_ES_LANG, - "zh-cn": ZH_CN_LANG -}; +import { SERVICE_CONFIG, IServiceConfig } from '../service.config'; /** * Declare a translation loader with local json object @@ -24,8 +12,15 @@ export const langs: { [key: string]: any } = { * @extends {TranslateLoader} */ export class TranslatorJsonLoader extends TranslateLoader { + constructor(private config: IServiceConfig) { + super(); + } + getTranslation(lang: string): Observable { - let dict: any = langs[lang] ? langs[lang] : {}; + let dict: any = this.config && + this.config.localI18nMessageVariableMap && + this.config.localI18nMessageVariableMap[lang] ? + this.config.localI18nMessageVariableMap[lang] : {}; return Observable.of(dict); } } \ No newline at end of file diff --git a/src/ui_ng/lib/src/i18n/translate-init.service.ts b/src/ui_ng/lib/src/i18n/translate-init.service.ts new file mode 100644 index 000000000..f756812fe --- /dev/null +++ b/src/ui_ng/lib/src/i18n/translate-init.service.ts @@ -0,0 +1,37 @@ +import { Injectable } from "@angular/core"; +import { i18nConfig } from "./i18n-config"; +import { TranslateService } from '@ngx-translate/core'; +import { DEFAULT_LANG_COOKIE_KEY, DEFAULT_SUPPORTING_LANGS, DEFAULT_LANG } from '../utils'; +import { CookieService } from 'ngx-cookie'; + +@Injectable() +export class TranslateServiceInitializer { + constructor( + private translateService: TranslateService, + private cookie: CookieService + ) { } + + public init(config: i18nConfig = {}): void { + let selectedLang: string = config.defaultLang ? config.defaultLang : DEFAULT_LANG; + + this.translateService.addLangs(config.supportedLangs ? config.supportedLangs : DEFAULT_SUPPORTING_LANGS); + this.translateService.setDefaultLang(selectedLang); + + if (config.enablei18Support) { + //If user has selected lang, then directly use it + let langSetting: string = this.cookie.get(config.langCookieKey ? config.langCookieKey : DEFAULT_LANG_COOKIE_KEY); + if (!langSetting || langSetting.trim() === "") { + //Use browser lang + langSetting = this.translateService.getBrowserCultureLang().toLowerCase(); + } + + if (config.supportedLangs && config.supportedLangs.length > 0) { + if (config.supportedLangs.find(lang => lang === langSetting)) { + selectedLang = langSetting; + } + } + } + + this.translateService.use(selectedLang); + } +} \ No newline at end of file diff --git a/src/ui_ng/lib/src/i18n/translate.spec.ts b/src/ui_ng/lib/src/i18n/translate.spec.ts index 549cd71b9..cacba29b1 100644 --- a/src/ui_ng/lib/src/i18n/translate.spec.ts +++ b/src/ui_ng/lib/src/i18n/translate.spec.ts @@ -3,13 +3,36 @@ import { SharedModule } from '../shared/shared.module'; import { TranslateService } from '@ngx-translate/core'; import { DEFAULT_LANG } from '../utils'; +import { SERVICE_CONFIG, IServiceConfig } from '../service.config'; + +const EN_US_LANG: any = { + "SIGN_UP": { + "TITLE": "Sign Up" + }, +} + +const ZH_CN_LANG: any = { + "SIGN_UP": { + "TITLE": "注册" + }, +} + describe('TranslateService', () => { + let testConfig: IServiceConfig = { + langMessageLoader: 'local', + localI18nMessageVariableMap: { + "en-us": EN_US_LANG, + "zh-cn": ZH_CN_LANG + } + }; beforeEach(() => { TestBed.configureTestingModule({ imports: [ SharedModule ], - providers: [] + providers: [{ + provide: SERVICE_CONFIG, useValue: testConfig + }] }); }); @@ -25,8 +48,8 @@ describe('TranslateService', () => { it('should translate key to text [en-us]', inject([TranslateService], (service: TranslateService) => { service.use(DEFAULT_LANG); - service.get('APP_TITLE.HARBOR').subscribe(text => { - expect(text).toEqual('Harbor'); + service.get('SIGN_UP.TITLE').subscribe(text => { + expect(text).toEqual('Sign Up'); }); })); diff --git a/src/ui_ng/lib/src/index.ts b/src/ui_ng/lib/src/index.ts index 2a6a85c13..ffa456caa 100644 --- a/src/ui_ng/lib/src/index.ts +++ b/src/ui_ng/lib/src/index.ts @@ -9,4 +9,5 @@ export * from './endpoint/index'; export * from './repository/index'; export * from './tag/index'; export * from './replication/index'; -export * from './vulnerability-scanning/index'; \ No newline at end of file +export * from './vulnerability-scanning/index'; +export * from './i18n/index'; \ No newline at end of file diff --git a/src/ui_ng/lib/src/list-repository/list-repository.component.spec.ts b/src/ui_ng/lib/src/list-repository/list-repository.component.spec.ts index fdc0a83c6..250bd13bb 100644 --- a/src/ui_ng/lib/src/list-repository/list-repository.component.spec.ts +++ b/src/ui_ng/lib/src/list-repository/list-repository.component.spec.ts @@ -1,5 +1,5 @@ -import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { DebugElement } from '@angular/core'; @@ -8,33 +8,35 @@ import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation import { ListRepositoryComponent } from './list-repository.component'; import { Repository } from '../service/interface'; -describe('ListRepositoryComponent (inline template)', ()=> { - +import { SERVICE_CONFIG, IServiceConfig } from '../service.config'; + +describe('ListRepositoryComponent (inline template)', () => { + let comp: ListRepositoryComponent; let fixture: ComponentFixture; let mockData: Repository[] = [ { - "id": 11, - "name": "library/busybox", - "project_id": 1, - "description": "", - "pull_count": 0, - "star_count": 0, - "tags_count": 1 + "id": 11, + "name": "library/busybox", + "project_id": 1, + "description": "", + "pull_count": 0, + "star_count": 0, + "tags_count": 1 }, { - "id": 12, - "name": "library/nginx", - "project_id": 1, - "description": "", - "pull_count": 0, - "star_count": 0, - "tags_count": 1 + "id": 12, + "name": "library/nginx", + "project_id": 1, + "description": "", + "pull_count": 0, + "star_count": 0, + "tags_count": 1 } - ]; + ]; - beforeEach(async(()=>{ + beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ SharedModule @@ -43,19 +45,19 @@ describe('ListRepositoryComponent (inline template)', ()=> { ListRepositoryComponent, ConfirmationDialogComponent ], - providers: [] + providers: [{ provide: SERVICE_CONFIG, useValue: {} }] }); })); - beforeEach(()=>{ + beforeEach(() => { fixture = TestBed.createComponent(ListRepositoryComponent); comp = fixture.componentInstance; }); - it('should load and render data', async(()=>{ + it('should load and render data', async(() => { fixture.detectChanges(); comp.repositories = mockData; - fixture.whenStable().then(()=>{ + fixture.whenStable().then(() => { fixture.detectChanges(); expect(comp.repositories).toBeTruthy(); let de: DebugElement = fixture.debugElement.query(By.css('datagrid-cell')); diff --git a/src/ui_ng/lib/src/service.config.ts b/src/ui_ng/lib/src/service.config.ts index 37badc95b..40281feec 100644 --- a/src/ui_ng/lib/src/service.config.ts +++ b/src/ui_ng/lib/src/service.config.ts @@ -3,6 +3,16 @@ import { OpaqueToken } from '@angular/core'; export let SERVICE_CONFIG = new OpaqueToken("service.config"); export interface IServiceConfig { + /** + * The base endpoint of service used to retrieve the system configuration information. + * The configurations may include but not limit: + * Notary configurations + * Registry configuration + * Volume information + * + * @type {string} + * @memberOf IServiceConfig + */ systemInfoEndpoint?: string; /** @@ -62,6 +72,22 @@ export interface IServiceConfig { */ replicationJobEndpoint?: string; + /** + * The base endpoint of the service used to handle vulnerability scanning. + * + * @type {string} + * @memberOf IServiceConfig + */ + vulnerabilityScanningBaseEndpoint?: string; + + /** + * To determine whether or not to enable the i18 multiple languages supporting. + * + * @type {boolean} + * @memberOf IServiceConfig + */ + enablei18Support?: boolean; + /** * The cookie key used to store the current used language preference. * @@ -79,18 +105,71 @@ export interface IServiceConfig { supportedLangs?: string[], /** - * To determine whether to not enable the i18 multiple languages supporting. + * Define the default language the translate service uses. * - * @type {boolean} - * @memberOf IServiceConfig + * @type {string} + * @memberOf i18nConfig */ - enablei18Support?: boolean; + defaultLang?: string; /** - * The base endpoint of the service used to handle vulnerability scanning. + * To determine which loader will be used to load the required lang messages. + * Support two loaders: + * One is 'http', use async http to load json files with the specified url/path. + * Another is 'local', use local json variable to store the lang message. * * @type {string} * @memberOf IServiceConfig */ - vulnerabilityScanningBaseEndpoint?: string; + langMessageLoader?: string; + + /** + * Define the basic url/path prefix for the loader to find the json files if the 'langMessageLoader' is 'http'. + * For example, 'src/i18n/langs'. + * + * @type {string} + * @memberOf IServiceConfig + */ + langMessagePathForHttpLoader?: string; + + /** + * Define the suffix of the json file names without lang name if 'langMessageLoader' is 'http'. + * For example, '-lang.json' is suffix of message file 'en-us-lang.json'. + * + * @type {string} + * @memberOf IServiceConfig + */ + langMessageFileSuffixForHttpLoader?: string; + + /** + * If set 'local' loader in configuration property 'langMessageLoader' to load the i18n messages, + * this property must be defined to tell local JSON loader where to get the related messages. + * E.g: + * If declare the following messages storage variables, + * + * export const EN_US_LANG: any = { + * "APP_TITLE": { + * "VMW_HARBOR": "VMware Harbor", + * "HARBOR": "Harbor" + * } + * } + * + * export const ZH_CN_LANG: any = { + * "APP_TITLE": { + * "VMW_HARBOR": "VMware Harbor中文版", + * "HARBOR": "Harbor" + * } + * } + * + * then this property should be set to: + * { + * "en-us": EN_US_LANG, + * "zh-cn": ZH_CN_LANG + * }; + * + * + * @type {{ [key: string]: any }} + * @memberOf IServiceConfig + */ + localI18nMessageVariableMap?: { [key: string]: any }; } \ No newline at end of file diff --git a/src/ui_ng/lib/src/shared/shared.module.ts b/src/ui_ng/lib/src/shared/shared.module.ts index 95108e1d3..dba8417cd 100644 --- a/src/ui_ng/lib/src/shared/shared.module.ts +++ b/src/ui_ng/lib/src/shared/shared.module.ts @@ -7,14 +7,25 @@ import { TranslateModule, TranslateLoader, TranslateService, MissingTranslationH import { MyMissingTranslationHandler } from '../i18n/missing-trans.handler'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { TranslatorJsonLoader } from '../i18n/local-json.loader'; - +import { IServiceConfig, SERVICE_CONFIG } from '../service.config'; +import { CookieService, CookieModule } from 'ngx-cookie'; /*export function HttpLoaderFactory(http: Http) { return new TranslateHttpLoader(http, 'i18n/lang/', '-lang.json'); -}*/ +} export function LocalJsonLoaderFactory() { return new TranslatorJsonLoader(); +}*/ + +export function GeneralTranslatorLoader(http: Http, config: IServiceConfig) { + if (config && config.langMessageLoader === 'http') { + let prefix: string = config.langMessagePathForHttpLoader ? config.langMessagePathForHttpLoader : "i18n/lang/"; + let suffix: string = config.langMessageFileSuffixForHttpLoader ? config.langMessageFileSuffixForHttpLoader : "-lang.json"; + return new TranslateHttpLoader(http, prefix, suffix); + } else { + return new TranslatorJsonLoader(config); + } } /** @@ -29,11 +40,13 @@ export function LocalJsonLoaderFactory() { CommonModule, HttpModule, FormsModule, + CookieModule.forRoot(), ClarityModule.forRoot(), TranslateModule.forRoot({ loader: { provide: TranslateLoader, - useFactory: (LocalJsonLoaderFactory) + useFactory: (GeneralTranslatorLoader), + deps: [Http, SERVICE_CONFIG] }, missingTranslationHandler: { provide: MissingTranslationHandler, @@ -45,9 +58,11 @@ export function LocalJsonLoaderFactory() { CommonModule, HttpModule, FormsModule, + CookieModule, ClarityModule, TranslateModule - ] + ], + providers: [CookieService] }) export class SharedModule { } \ No newline at end of file diff --git a/src/ui_ng/lib/src/vulnerability-scanning/result-tip.component.spec.ts b/src/ui_ng/lib/src/vulnerability-scanning/result-tip.component.spec.ts index b3f2332dc..824037ff6 100644 --- a/src/ui_ng/lib/src/vulnerability-scanning/result-tip.component.spec.ts +++ b/src/ui_ng/lib/src/vulnerability-scanning/result-tip.component.spec.ts @@ -8,16 +8,22 @@ import { ScanningDetailResult, VulnerabilitySeverity } from '../service/index'; import { ResultTipComponent } from './result-tip.component'; import { SharedModule } from '../shared/shared.module'; +import { SERVICE_CONFIG, IServiceConfig } from '../service.config'; + describe('ResultTipComponent (inline template)', () => { let component: ResultTipComponent; let fixture: ComponentFixture; + let testConfig: IServiceConfig = { + vulnerabilityScanningBaseEndpoint: "/api/vulnerability/testing" + }; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ SharedModule ], - declarations: [ResultTipComponent] + declarations: [ResultTipComponent], + providers: [{ provide: SERVICE_CONFIG, useValue: testConfig }] }); }));