1
0
mirror of https://github.com/bitwarden/web synced 2025-12-06 00:03:28 +00:00

Compare commits

...

74 Commits

Author SHA1 Message Date
Kyle Spearrin
2f27decaa1 bump version 2018-11-26 15:36:17 -05:00
Kyle Spearrin
867115659f re-enable key rotation on master password change 2018-11-26 15:36:09 -05:00
Kyle Spearrin
6282ab58db hide key rotation option 2018-11-26 12:59:45 -05:00
Kyle Spearrin
95c25c1bcd fix help articles 2018-11-26 12:25:27 -05:00
Kyle Spearrin
74a62de7d0 New Crowdin translations (#295)
* New translations messages.json (Czech)

* New translations messages.json (Danish)

* New translations messages.json (Dutch)

* New translations messages.json (French)

* New translations messages.json (Italian)

* New translations messages.json (Japanese)

* New translations messages.json (Norwegian Bokmal)

* New translations messages.json (Polish)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese, Brazilian)

* New translations messages.json (Russian)

* New translations messages.json (Slovak)

* New translations messages.json (Spanish)
2018-11-26 08:41:59 -05:00
Kyle Spearrin
7fc021648d update jslib 2018-11-26 08:31:28 -05:00
Kyle Spearrin
95914ad312 Merge branch 'master' of github.com:bitwarden/web 2018-11-23 08:20:25 -05:00
Kyle Spearrin
5ed00e037a bump version 2018-11-23 08:20:22 -05:00
Kyle Spearrin
6f3074536a New Crowdin translations (#292)
* New translations messages.json (Chinese Simplified)

* New translations messages.json (Korean)

* New translations messages.json (Turkish)

* New translations messages.json (Swedish)

* New translations messages.json (Spanish)

* New translations messages.json (Slovak)

* New translations messages.json (Russian)

* New translations messages.json (Portuguese, Brazilian)

* New translations messages.json (Portuguese)

* New translations messages.json (Polish)

* New translations messages.json (Norwegian Bokmal)

* New translations messages.json (Japanese)

* New translations messages.json (Chinese Traditional)

* New translations messages.json (Italian)

* New translations messages.json (Hungarian)

* New translations messages.json (German)

* New translations messages.json (French)

* New translations messages.json (Finnish)

* New translations messages.json (Estonian)

* New translations messages.json (Dutch)

* New translations messages.json (Danish)

* New translations messages.json (Czech)

* New translations messages.json (Ukrainian)
2018-11-21 09:16:53 -05:00
Kyle Spearrin
21f5cb36bb To ensure the integrity 2018-11-21 09:04:46 -05:00
Kyle Spearrin
7b7592822f New Crowdin translations (#290)
* New translations messages.json (Chinese Simplified)

* New translations messages.json (Korean)

* New translations messages.json (Turkish)

* New translations messages.json (Swedish)

* New translations messages.json (Spanish)

* New translations messages.json (Slovak)

* New translations messages.json (Russian)

* New translations messages.json (Portuguese, Brazilian)

* New translations messages.json (Portuguese)

* New translations messages.json (Polish)

* New translations messages.json (Norwegian Bokmal)

* New translations messages.json (Japanese)

* New translations messages.json (Chinese Traditional)

* New translations messages.json (Italian)

* New translations messages.json (Hungarian)

* New translations messages.json (German)

* New translations messages.json (French)

* New translations messages.json (Finnish)

* New translations messages.json (Estonian)

* New translations messages.json (Dutch)

* New translations messages.json (Danish)

* New translations messages.json (Czech)

* New translations messages.json (Ukrainian)
2018-11-20 22:35:17 -05:00
Kyle Spearrin
9c7b7b0d75 premium access addon for orgs 2018-11-20 16:38:00 -05:00
Kyle Spearrin
d88b23c42d learn more about encryption key changes from help article 2018-11-20 13:05:52 -05:00
Kyle Spearrin
1602c0aca2 link to fingerprint phrase article 2018-11-16 11:20:44 -05:00
Kyle Spearrin
384978a511 fix old attachments article info 2018-11-16 09:17:33 -05:00
Kyle Spearrin
afd7a0494f fix password meter aria-valuenow 2018-11-15 14:46:51 -05:00
Kyle Spearrin
ac1f8a69e1 allow bulk sharing of items with new attachments 2018-11-15 12:56:07 -05:00
Kyle Spearrin
05cfa99ea0 fingerprint phrase confirmation 2018-11-14 23:13:50 -05:00
Kyle Spearrin
9b43ccbbc0 updateKey helper 2018-11-14 16:22:57 -05:00
Kyle Spearrin
6d8b156455 old attachments check when rotating enc key 2018-11-14 15:54:13 -05:00
Kyle Spearrin
1b9943a4c8 allow swal single button 2018-11-14 15:45:03 -05:00
Kyle Spearrin
8232a4c9c8 fix old attachments by reuploading them 2018-11-14 15:20:17 -05:00
Kyle Spearrin
9d4d64c95a update jslib 2018-11-13 20:43:56 -05:00
Kyle Spearrin
2d0acc7663 add enc key rotation option during master password change 2018-11-13 11:06:16 -05:00
Kyle Spearrin
4231ed74ba adjust password strength meter 2018-11-13 09:10:44 -05:00
Kyle Spearrin
912e1cf89f getPasswordStrengthUserInput on password change 2018-11-12 23:26:00 -05:00
Kyle Spearrin
26d4fb8005 fix aslignment with invisible progress bar 2018-11-12 23:06:28 -05:00
Kyle Spearrin
4a6c0b39a8 add typings for zxcvbn 2018-11-12 23:03:20 -05:00
Kyle Spearrin
9d01bba170 weak password checks on master password change 2018-11-12 23:00:58 -05:00
Kyle Spearrin
85c0ddba10 password strength checks during registration 2018-11-12 22:54:40 -05:00
Kyle Spearrin
2664059812 caret spacing 2018-11-09 22:25:07 -05:00
Kyle Spearrin
b7e4d9c806 toggle collapse string update 2018-11-09 17:50:26 -05:00
Kyle Spearrin
95b91f0ce2 added collpase/expand functions to groupings 2018-11-09 17:45:01 -05:00
Kyle Spearrin
f0407e4327 catch any errors when generating fingerprint 2018-11-07 23:19:48 -05:00
Kyle Spearrin
a7555f56e7 print user's fingerprint when confirming 2018-11-07 23:15:50 -05:00
Kyle Spearrin
b093ed33b2 update jslib 2018-11-06 15:53:51 -05:00
Kyle Spearrin
ec1a45ba18 update jslib 2018-11-06 15:51:52 -05:00
Kyle Spearrin
def5dc3b0f New Crowdin translations (#286)
* New translations messages.json (Chinese Simplified)

* New translations messages.json (Chinese Traditional)

* New translations messages.json (Danish)

* New translations messages.json (Dutch)

* New translations messages.json (Estonian)

* New translations messages.json (Finnish)

* New translations messages.json (French)

* New translations messages.json (Japanese)

* New translations messages.json (Norwegian Bokmal)

* New translations messages.json (Polish)

* New translations messages.json (Portuguese)

* New translations messages.json (Portuguese, Brazilian)

* New translations messages.json (Russian)

* New translations messages.json (Spanish)
2018-11-06 15:51:05 -05:00
Kyle Spearrin
24ec89c220 open PDF in new window using built-in browser viewer 2018-11-06 09:46:17 -05:00
Kyle Spearrin
303e70bb58 update jslib 2018-11-06 09:05:46 -05:00
Kyle Spearrin
ec3e92fc19 set blob type 2018-10-30 09:54:14 -04:00
Kyle Spearrin
5ae776309d New Crowdin translations (#284)
* New translations messages.json (Chinese Simplified)

* New translations messages.json (Korean)

* New translations messages.json (Turkish)

* New translations messages.json (Swedish)

* New translations messages.json (Spanish)

* New translations messages.json (Slovak)

* New translations messages.json (Russian)

* New translations messages.json (Portuguese, Brazilian)

* New translations messages.json (Portuguese)

* New translations messages.json (Polish)

* New translations messages.json (Norwegian Bokmal)

* New translations messages.json (Japanese)

* New translations messages.json (Chinese Traditional)

* New translations messages.json (Italian)

* New translations messages.json (Hungarian)

* New translations messages.json (German)

* New translations messages.json (French)

* New translations messages.json (Finnish)

* New translations messages.json (Estonian)

* New translations messages.json (Dutch)

* New translations messages.json (Danish)

* New translations messages.json (Czech)

* New translations messages.json (Ukrainian)
2018-10-29 10:26:38 -04:00
Kyle Spearrin
76dd606a48 additionalStorageIntervalDesc 2018-10-29 10:07:03 -04:00
Kyle Spearrin
8998798fa4 always load nested collections 2018-10-29 10:06:42 -04:00
Kyle Spearrin
60ee82ca47 always loading nested now 2018-10-26 10:49:14 -04:00
Kyle Spearrin
e1284002a9 cleanup imports 2018-10-26 08:29:33 -04:00
Kyle Spearrin
8252512784 nested collections 2018-10-25 12:19:35 -04:00
Kyle Spearrin
1390d7eb1d display nested folders 2018-10-25 09:38:52 -04:00
Kyle Spearrin
8da1bb13ff dont stop prob on label simple label click for cb list 2018-10-24 22:15:09 -04:00
Kyle Spearrin
340e377b37 filter collections for current org 2018-10-24 22:09:36 -04:00
Kyle Spearrin
171589fb3d missing searchText property 2018-10-24 22:01:38 -04:00
Kyle Spearrin
bcd07cce0d New Crowdin translations (#281)
* New translations messages.json (Chinese Simplified)

* New translations messages.json (Korean)

* New translations messages.json (Turkish)

* New translations messages.json (Swedish)

* New translations messages.json (Spanish)

* New translations messages.json (Slovak)

* New translations messages.json (Russian)

* New translations messages.json (Portuguese, Brazilian)

* New translations messages.json (Portuguese)

* New translations messages.json (Polish)

* New translations messages.json (Norwegian Bokmal)

* New translations messages.json (Japanese)

* New translations messages.json (Chinese Traditional)

* New translations messages.json (Italian)

* New translations messages.json (Hungarian)

* New translations messages.json (German)

* New translations messages.json (French)

* New translations messages.json (Finnish)

* New translations messages.json (Estonian)

* New translations messages.json (Dutch)

* New translations messages.json (Danish)

* New translations messages.json (Czech)

* New translations messages.json (Ukrainian)
2018-10-24 13:03:03 -04:00
Kyle Spearrin
68880114b4 bump version 2018-10-23 22:57:36 -04:00
Kyle Spearrin
eb2360ae24 update jslib 2018-10-23 16:18:01 -04:00
Kyle Spearrin
62712a352b update jslib 2018-10-23 12:04:28 -04:00
Kyle Spearrin
745e6c1715 use base collections component from jslib 2018-10-23 12:04:05 -04:00
Kyle Spearrin
e20a75eb0c use share component from jslib 2018-10-23 10:33:40 -04:00
Kyle Spearrin
a24c41ff25 set org id and collections if filtered 2018-10-22 16:46:48 -04:00
Kyle Spearrin
69f0339bd5 set collections for org admin 2018-10-22 14:48:17 -04:00
Kyle Spearrin
5e7c9a7278 add ownership and collection assignment from add/edit 2018-10-19 12:44:52 -04:00
Kyle Spearrin
726c323fe1 accessAll is only for collection assignments 2018-10-18 12:25:25 -04:00
SoulSeekkor
e96cbe2710 Added .gitattributes file to files requiring LF endings are properly checked out on Windows. (#279) 2018-10-18 12:15:54 -04:00
Kyle Spearrin
323e54b4bd filtering 2018-10-18 12:15:13 -04:00
Kyle Spearrin
7ab132bbf6 add thead for entity users 2018-10-17 23:04:39 -04:00
Kyle Spearrin
6b09210a80 manage group users 2018-10-17 22:56:49 -04:00
Kyle Spearrin
be80d62c01 manage collection users for entity-users 2018-10-17 22:20:42 -04:00
Kyle Spearrin
30587d625a fixes to showAdd and filtering on load for non-admins 2018-10-17 16:09:09 -04:00
Kyle Spearrin
af43cd407e undo manage rules for org groupings listing 2018-10-17 15:57:39 -04:00
Kyle Spearrin
647388e475 showAddNew only if admin 2018-10-17 15:51:31 -04:00
Kyle Spearrin
329e06ac30 null check in view 2018-10-17 15:46:13 -04:00
Kyle Spearrin
5d96138720 lint fix 2018-10-17 11:23:01 -04:00
Kyle Spearrin
66b275605c load manage collections a manager has access to 2018-10-17 11:20:27 -04:00
Kyle Spearrin
9b7478c0c7 manager sees their assigned collections from org vault view 2018-10-17 11:19:10 -04:00
Kyle Spearrin
668271bb31 add basic org manager access and UI elements 2018-10-17 10:53:04 -04:00
81 changed files with 4453 additions and 1513 deletions

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
*.sh eol=lf
.dockerignore eol=lf
dockerfile eol=lf

2
jslib

Submodule jslib updated: 2f6426deb4...64a6015a67

18
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "bitwarden-web",
"version": "2.4.0",
"version": "2.6.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -591,6 +591,12 @@
"source-map": "^0.6.0"
}
},
"@types/zxcvbn": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@types/zxcvbn/-/zxcvbn-4.4.0.tgz",
"integrity": "sha512-GQLOT+SN20a+AI51y3fAimhyTF4Y0RG+YP3gf91OibIZ7CJmPFgoZi+ZR5a+vRbS01LbQosITWum4ATmJ1Z6Pg==",
"dev": true
},
"@webassemblyjs/ast": {
"version": "1.7.6",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.6.tgz",
@@ -1271,6 +1277,11 @@
"integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=",
"dev": true
},
"big-integer": {
"version": "1.6.36",
"resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz",
"integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg=="
},
"big.js": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
@@ -11998,6 +12009,11 @@
"version": "0.8.26",
"resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.26.tgz",
"integrity": "sha512-W9Nj+UmBJG251wkCacIkETgra4QgBo/vgoEkb4a2uoLzpQG7qF9nzwoLXWU5xj3Fg2mxGvEDh47mg24vXccYjA=="
},
"zxcvbn": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz",
"integrity": "sha1-KOwXzwl0PtyrBW3dixsGJizHPDA="
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "bitwarden-web",
"version": "2.4.0",
"version": "2.6.1",
"scripts": {
"sub:init": "git submodule update --init --recursive",
"sub:update": "git submodule update --remote",
@@ -31,6 +31,7 @@
"@types/papaparse": "^4.5.3",
"@types/webcrypto": "^0.0.28",
"@types/webpack": "^4.4.11",
"@types/zxcvbn": "^4.4.0",
"angular2-template-loader": "^0.6.2",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.5.2",
@@ -70,6 +71,7 @@
"@aspnet/signalr-protocol-msgpack": "1.0.4",
"angular2-toaster": "6.1.0",
"angulartics2": "6.3.0",
"big-integer": "1.6.36",
"bootstrap": "4.1.3",
"braintree-web-drop-in": "1.13.0",
"core-js": "2.5.7",
@@ -87,6 +89,7 @@
"web-animations-js": "2.3.1",
"webcrypto-shim": "0.1.4",
"whatwg-fetch": "3.0.0",
"zone.js": "0.8.26"
"zone.js": "0.8.26",
"zxcvbn": "4.4.2"
}
}

View File

@@ -21,11 +21,17 @@
<div class="form-group">
<label for="masterPassword">{{'masterPass' | i18n}}</label>
<div class="d-flex">
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword" class="text-monospace form-control"
[(ngModel)]="masterPassword" required appInputVerbatim>
<button type="button" class="ml-1 btn btn-link" title="{{'toggleVisibility' | i18n}}" (click)="togglePassword(false)">
<i class="fa fa-lg" [ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</button>
<div class="w-100">
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword" class="text-monospace form-control mb-1"
[(ngModel)]="masterPassword" (input)="updatePasswordStrength()" required appInputVerbatim>
<app-password-strength [score]="masterPasswordScore" [showText]="true"></app-password-strength>
</div>
<div>
<button type="button" class="ml-1 btn btn-link" title="{{'toggleVisibility' | i18n}}" (click)="togglePassword(false)">
<i class="fa fa-lg" [ngClass]="{'fa-eye': !showPassword, 'fa-eye-slash': showPassword}"></i>
</button>
<div class="progress-bar invisible"></div>
</div>
</div>
<small class="form-text text-muted">{{'masterPassDesc' | i18n}}</small>
</div>

View File

@@ -8,6 +8,7 @@ import { ApiService } from 'jslib/abstractions/api.service';
import { AuthService } from 'jslib/abstractions/auth.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StateService } from 'jslib/abstractions/state.service';
@@ -24,8 +25,10 @@ export class RegisterComponent extends BaseRegisterComponent {
constructor(authService: AuthService, router: Router,
i18nService: I18nService, cryptoService: CryptoService,
apiService: ApiService, private route: ActivatedRoute,
stateService: StateService, platformUtilsService: PlatformUtilsService) {
super(authService, router, i18nService, cryptoService, apiService, stateService, platformUtilsService);
stateService: StateService, platformUtilsService: PlatformUtilsService,
passwordGenerationService: PasswordGenerationService) {
super(authService, router, i18nService, cryptoService, apiService, stateService, platformUtilsService,
passwordGenerationService);
this.showTerms = !platformUtilsService.isSelfHost();
}

View File

@@ -174,7 +174,13 @@ const routes: Routes = [
path: 'manage',
component: OrgManageComponent,
canActivate: [OrganizationTypeGuardService],
data: { allowedTypes: [OrganizationUserType.Owner, OrganizationUserType.Admin] },
data: {
allowedTypes: [
OrganizationUserType.Owner,
OrganizationUserType.Admin,
OrganizationUserType.Manager,
],
},
children: [
{ path: '', pathMatch: 'full', redirectTo: 'people' },
{ path: 'collections', component: OrgManageCollectionsComponent, data: { titleId: 'collections' } },

View File

@@ -18,6 +18,7 @@ import { ModalComponent } from './modal.component';
import { AvatarComponent } from './components/avatar.component';
import { CalloutComponent } from './components/callout.component';
import { PasswordStrengthComponent } from './components/password-strength.component';
import { FooterComponent } from './layouts/footer.component';
import { FrontendLayoutComponent } from './layouts/frontend-layout.component';
@@ -49,6 +50,7 @@ import { GroupsComponent as OrgGroupsComponent } from './organizations/manage/gr
import { ManageComponent as OrgManageComponent } from './organizations/manage/manage.component';
import { PeopleComponent as OrgPeopleComponent } from './organizations/manage/people.component';
import { UserAddEditComponent as OrgUserAddEditComponent } from './organizations/manage/user-add-edit.component';
import { UserConfirmComponent as OrgUserConfirmComponent } from './organizations/manage/user-confirm.component';
import { UserGroupsComponent as OrgUserGroupsComponent } from './organizations/manage/user-groups.component';
import { AccountComponent as OrgAccountComponent } from './organizations/settings/account.component';
@@ -252,6 +254,7 @@ registerLocaleData(localeZhCn, 'zh-CN');
OrgToolsComponent,
OrgTwoFactorSetupComponent,
OrgUserAddEditComponent,
OrgUserConfirmComponent,
OrgUserGroupsComponent,
OrganizationsComponent,
OrganizationLayoutComponent,
@@ -291,6 +294,7 @@ registerLocaleData(localeZhCn, 'zh-CN');
VerifyEmailComponent,
VerifyEmailTokenComponent,
VerifyRecoverDeleteComponent,
PasswordStrengthComponent,
],
entryComponents: [
AddEditComponent,
@@ -312,6 +316,7 @@ registerLocaleData(localeZhCn, 'zh-CN');
OrgEntityUsersComponent,
OrgGroupAddEditComponent,
OrgUserAddEditComponent,
OrgUserConfirmComponent,
OrgUserGroupsComponent,
PasswordGeneratorHistoryComponent,
PurgeVaultComponent,

View File

@@ -0,0 +1,8 @@
<div class="progress">
<div class="progress-bar {{color}}" role="progressbar" [ngStyle]="{width: (scoreWidth + '%')}" attr.aria-valuenow="{{scoreWidth}}"
aria-valuemin="0" aria-valuemax="100">
<ng-container *ngIf="showText && text">
{{text}}
</ng-container>
</div>
</div>

View File

@@ -0,0 +1,44 @@
import {
Component,
Input,
OnChanges,
} from '@angular/core';
import { I18nService } from 'jslib/abstractions/i18n.service';
@Component({
selector: 'app-password-strength',
templateUrl: 'password-strength.component.html',
})
export class PasswordStrengthComponent implements OnChanges {
@Input() score?: number;
@Input() showText = false;
scoreWidth = 0;
color = 'bg-danger';
text: string;
constructor(private i18nService: I18nService) { }
ngOnChanges(): void {
this.scoreWidth = this.score == null ? 0 : (this.score + 1) * 20;
switch (this.score) {
case 4:
this.color = 'bg-success';
this.text = this.i18nService.t('strong');
break;
case 3:
this.color = 'bg-primary';
this.text = this.i18nService.t('good');
break;
case 2:
this.color = 'bg-warning';
this.text = this.i18nService.t('weak');
break;
default:
this.color = 'bg-danger';
this.text = this.score != null ? this.i18nService.t('weak') : null;
break;
}
}
}

View File

@@ -14,7 +14,7 @@
</div>
</div>
</div>
<ul class="nav nav-tabs" *ngIf="organization.isAdmin">
<ul class="nav nav-tabs" *ngIf="organization.isManager">
<li class="nav-item">
<a class="nav-link" routerLink="vault" routerLinkActive="active">
<i class="fa fa-lock"></i>
@@ -27,7 +27,7 @@
{{'manage' | i18n}}
</a>
</li>
<li class="nav-item">
<li class="nav-item" *ngIf="organization.isAdmin">
<a class="nav-link" routerLink="tools" routerLinkActive="active">
<i class="fa fa-wrench"></i>
{{'tools' | i18n}}

View File

@@ -44,10 +44,8 @@
<input type="checkbox" [(ngModel)]="g.checked" name="Groups[{{i}}].Checked" [disabled]="g.accessAll" appStopProp>
</td>
<td (click)="check(g)">
<span appStopProp>
{{g.name}}
<i class="fa fa-th text-muted fa-fw" *ngIf="g.accessAll" title="This group can access all items"></i>
</span>
{{g.name}}
<i class="fa fa-th text-muted fa-fw" *ngIf="g.accessAll" title="This group can access all items"></i>
</td>
<td class="text-center">
<input type="checkbox" [(ngModel)]="g.readOnly" name="Groups[{{i}}].ReadOnly" [disabled]="!g.checked || g.accessAll">
@@ -64,8 +62,8 @@
</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'cancel' | i18n}}</button>
<div class="ml-auto">
<button #deleteBtn type="button" (click)="delete()" class="btn btn-outline-danger" title="{{'delete' | i18n}}" *ngIf="editMode"
[disabled]="deleteBtn.loading" [appApiAction]="deletePromise">
<button #deleteBtn type="button" (click)="delete()" class="btn btn-outline-danger" title="{{'delete' | i18n}}"
*ngIf="editMode" [disabled]="deleteBtn.loading" [appApiAction]="deletePromise">
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading" title="{{'loading' | i18n}}"></i>
</button>

View File

@@ -14,10 +14,15 @@ import { ApiService } from 'jslib/abstractions/api.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { UserService } from 'jslib/abstractions/user.service';
import { CollectionData } from 'jslib/models/data/collectionData';
import { Collection } from 'jslib/models/domain/collection';
import { CollectionDetailsResponse } from 'jslib/models/response/collectionResponse';
import {
CollectionDetailsResponse,
CollectionResponse,
} from 'jslib/models/response/collectionResponse';
import { ListResponse } from 'jslib/models/response/listResponse';
import { CollectionView } from 'jslib/models/view/collectionView';
import { ModalComponent } from '../../modal.component';
@@ -42,7 +47,8 @@ export class CollectionsComponent implements OnInit {
constructor(private apiService: ApiService, private route: ActivatedRoute,
private collectionService: CollectionService, private componentFactoryResolver: ComponentFactoryResolver,
private analytics: Angulartics2, private toasterService: ToasterService,
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService) { }
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
private userService: UserService) { }
async ngOnInit() {
this.route.parent.parent.params.subscribe(async (params) => {
@@ -55,8 +61,14 @@ export class CollectionsComponent implements OnInit {
}
async load() {
const response = await this.apiService.getCollections(this.organizationId);
const collections = response.data.map((r) =>
const organization = await this.userService.getOrganization(this.organizationId);
let response: ListResponse<CollectionResponse>;
if (organization.isAdmin) {
response = await this.apiService.getCollections(this.organizationId);
} else {
response = await this.apiService.getUserCollections();
}
const collections = response.data.filter((c) => c.organizationId === this.organizationId).map((r) =>
new Collection(new CollectionData(r as CollectionDetailsResponse)));
this.collections = await this.collectionService.decryptMany(collections);
this.loading = false;
@@ -123,6 +135,10 @@ export class CollectionsComponent implements OnInit {
childComponent.entityId = collection.id;
childComponent.entityName = collection.name;
childComponent.onEditedUsers.subscribe(() => {
this.load();
this.modal.close();
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});

View File

@@ -1,6 +1,6 @@
<div class="modal fade">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise" ngNativeValidate>
<div class="modal-header">
<h2 class="modal-title">
{{'userAccess' | i18n}}
@@ -10,48 +10,88 @@
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body" *ngIf="loading">
<div class="modal-body" *ngIf="loading || !users">
<i class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}"></i>
</div>
<div class="modal-body" *ngIf="!loading">
<ng-container *ngIf="!users || !users.length">
<div class="modal-body" *ngIf="!loading && users && (users | search:searchText:'name':'email':'id') as searchedUsers">
<div class="d-flex">
<div class="mr-3">
<label class="sr-only" for="search">{{'search' | i18n}}</label>
<input type="search" class="form-control form-control-sm" id="search" placeholder="{{'search' | i18n}}"
name="SearchText" [(ngModel)]="searchText">
</div>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-secondary" [ngClass]="{active: !showSelected}"
(click)="filterSelected(false)">
{{'all' | i18n}}
</button>
<button type="button" class="btn btn-outline-secondary" [ngClass]="{active: showSelected}"
(click)="filterSelected(true)">
{{'selected' | i18n}}
<span class="badge badge-pill badge-info" *ngIf="selectedCount">{{selectedCount}}</span>
</button>
</div>
</div>
<ng-container *ngIf="!searchedUsers.length">
<hr>
{{'noUsersInList' | i18n}}
</ng-container>
<table class="table table-hover table-list mb-0" *ngIf="users && users.length">
<tbody>
<tr *ngFor="let u of users">
<td width="30">
<app-avatar [data]="u.name || u.email" [email]="u.email" size="25" [circle]="true" [fontSize]="14"></app-avatar>
</td>
<td>
{{u.email}}
<span class="badge badge-secondary" *ngIf="u.status === organizationUserStatusType.Invited">{{'invited' | i18n}}</span>
<span class="badge badge-warning" *ngIf="u.status === organizationUserStatusType.Accepted">{{'accepted' | i18n}}</span>
<small class="text-muted d-block" *ngIf="u.name">{{u.name}}</small>
</td>
<td *ngIf="entity === 'collection'">
<i class="fa fa-th" *ngIf="u.accessAll" title="{{'userAccessAllItems' | i18n}}"></i>
<i class="fa fa-eye" *ngIf="u.readOnly" title="{{'readOnly' | i18n}}"></i>
</td>
<td>
<span *ngIf="u.type === organizationUserType.Owner">{{'owner' | i18n}}</span>
<span *ngIf="u.type === organizationUserType.Admin">{{'admin' | i18n}}</span>
<span *ngIf="u.type === organizationUserType.User">{{'user' | i18n}}</span>
</td>
<td class="table-list-options wider">
<button type="button" class="btn btn-sm btn-outline-danger btn-submit" (click)="remove(u)" #removeBtn [disabled]="removeBtn.loading"
[appApiAction]="actionPromise" *ngIf="entity !== 'collection' || !u.accessAll">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}"></i>
<span>{{'remove' | i18n}}</span>
</button>
</td>
</tr>
</tbody>
</table>
<ng-container *ngIf="searchedUsers.length">
<table class="table table-hover table-list mb-0">
<thead>
<tr>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>{{'name' | i18n}}</th>
<th *ngIf="entity === 'collection'">&nbsp;</th>
<th>{{'userType' | i18n}}</th>
<th width="100" class="text-center" *ngIf="entity === 'collection'">{{'readOnly' |
i18n}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let u of searchedUsers">
<td class="table-list-checkbox" (click)="check(u)">
<input type="checkbox" [(ngModel)]="u.checked" name="{{u.id.substr(0,8)}}_Checked"
[disabled]="entity === 'collection' && u.accessAll" (change)="selectedChanged(u)" appStopProp>
</td>
<td width="30" (click)="check(u)">
<app-avatar [data]="u.name || u.email" [email]="u.email" size="25" [circle]="true"
[fontSize]="14"></app-avatar>
</td>
<td>
{{u.email}}
<span class="badge badge-secondary" *ngIf="u.status === organizationUserStatusType.Invited">{{'invited'
| i18n}}</span>
<span class="badge badge-warning" *ngIf="u.status === organizationUserStatusType.Accepted">{{'accepted'
| i18n}}</span>
<small class="text-muted d-block" *ngIf="u.name">{{u.name}}</small>
</td>
<td *ngIf="entity === 'collection'">
<i class="fa fa-th" *ngIf="u.accessAll" title="{{'userAccessAllItems' | i18n}}"></i>
</td>
<td>
<span *ngIf="u.type === organizationUserType.Owner">{{'owner' | i18n}}</span>
<span *ngIf="u.type === organizationUserType.Admin">{{'admin' | i18n}}</span>
<span *ngIf="u.type === organizationUserType.Manager">{{'manager' | i18n}}</span>
<span *ngIf="u.type === organizationUserType.User">{{'user' | i18n}}</span>
</td>
<td class="text-center" *ngIf="entity === 'collection'">
<input type="checkbox" [(ngModel)]="u.readOnly" name="{{u.id.substr(0,8)}}_ReadOnly"
[disabled]="u.accessAll || !u.checked">
</td>
</tr>
</tbody>
</table>
</ng-container>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}"></i>
<span>{{'save' | i18n}}</span>
</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
</div>
</div>
</form>
</div>
</div>

View File

@@ -11,10 +11,11 @@ import { Angulartics2 } from 'angulartics2';
import { ApiService } from 'jslib/abstractions/api.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { OrganizationUserStatusType } from 'jslib/enums/organizationUserStatusType';
import { OrganizationUserType } from 'jslib/enums/organizationUserType';
import { SelectionReadOnlyRequest } from 'jslib/models/request/selectionReadOnlyRequest';
import { OrganizationUserUserDetailsResponse } from 'jslib/models/response/organizationUserResponse';
import { Utils } from 'jslib/misc/utils';
@@ -27,68 +28,110 @@ export class EntityUsersComponent implements OnInit {
@Input() entityId: string;
@Input() entityName: string;
@Input() organizationId: string;
@Output() onRemovedUser = new EventEmitter();
@Output() onEditedUsers = new EventEmitter();
organizationUserType = OrganizationUserType;
organizationUserStatusType = OrganizationUserStatusType;
showSelected = false;
loading = true;
users: any[] = [];
actionPromise: Promise<any>;
formPromise: Promise<any>;
selectedCount = 0;
searchText: string;
private allUsers: OrganizationUserUserDetailsResponse[] = [];
constructor(private apiService: ApiService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService,
private platformUtilsService: PlatformUtilsService) { }
private analytics: Angulartics2, private toasterService: ToasterService) { }
async ngOnInit() {
await this.loadUsers();
this.loading = false;
}
async loadUsers() {
let users: any[] = [];
if (this.entity === 'group') {
const response = await this.apiService.getGroupUsers(this.organizationId, this.entityId);
users = response.data.map((r) => r);
} else if (this.entity === 'collection') {
const response = await this.apiService.getCollectionUsers(this.organizationId, this.entityId);
users = response.data.map((r) => r);
get users() {
if (this.showSelected) {
return this.allUsers.filter((u) => (u as any).checked);
} else {
return this.allUsers;
}
users.sort(Utils.getSortFunction(this.i18nService, 'email'));
this.users = users;
}
async remove(user: any) {
if (this.actionPromise != null || (this.entity === 'collection' && user.accessAll)) {
async loadUsers() {
const users = await this.apiService.getOrganizationUsers(this.organizationId);
this.allUsers = users.data.map((r) => r).sort(Utils.getSortFunction(this.i18nService, 'email'));
if (this.entity === 'group') {
const response = await this.apiService.getGroupUsers(this.organizationId, this.entityId);
if (response != null && users.data.length > 0) {
response.forEach((s) => {
const user = users.data.filter((u) => u.id === s);
if (user != null && user.length > 0) {
(user[0] as any).checked = true;
}
});
}
} else if (this.entity === 'collection') {
const response = await this.apiService.getCollectionUsers(this.organizationId, this.entityId);
if (response != null && users.data.length > 0) {
response.forEach((s) => {
const user = users.data.filter((u) => !u.accessAll && u.id === s.id);
if (user != null && user.length > 0) {
(user[0] as any).checked = true;
(user[0] as any).readOnly = s.readOnly;
}
});
}
}
this.allUsers.forEach((u) => {
if (this.entity === 'collection' && u.accessAll) {
(u as any).checked = true;
}
if ((u as any).checked) {
this.selectedCount++;
}
});
}
check(u: OrganizationUserUserDetailsResponse) {
if (this.entity === 'collection' && u.accessAll) {
return;
}
(u as any).checked = !(u as any).checked;
this.selectedChanged(u);
}
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('removeUserConfirmation'), user.email,
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
if (!confirmed) {
return false;
selectedChanged(u: OrganizationUserUserDetailsResponse) {
if ((u as any).checked) {
this.selectedCount++;
} else {
if (this.entity === 'collection') {
(u as any).readOnly = false;
}
this.selectedCount--;
}
}
filterSelected(showSelected: boolean) {
this.showSelected = showSelected;
}
async submit() {
try {
if (this.entity === 'group') {
this.actionPromise = this.apiService.deleteGroupUser(this.organizationId, this.entityId,
user.organizationUserId);
await this.actionPromise;
this.analytics.eventTrack.next({ action: 'Removed User From Group' });
} else if (this.entity === 'collection') {
this.actionPromise = this.apiService.deleteCollectionUser(this.organizationId, this.entityId,
user.organizationUserId);
await this.actionPromise;
this.analytics.eventTrack.next({ action: 'Removed User From Collection' });
}
this.toasterService.popAsync('success', null, this.i18nService.t('removedUserId', user.email));
this.onRemovedUser.emit();
const index = this.users.indexOf(user);
if (index > -1) {
this.users.splice(index, 1);
const selections = this.users.filter((u) => (u as any).checked).map((u) => u.id);
this.formPromise = this.apiService.putGroupUsers(this.organizationId, this.entityId, selections);
} else {
const selections = this.users.filter((u) => (u as any).checked && !u.accessAll)
.map((u) => new SelectionReadOnlyRequest(u.id, !!(u as any).readOnly));
this.formPromise = this.apiService.putCollectionUsers(this.organizationId, this.entityId, selections);
}
await this.formPromise;
this.analytics.eventTrack.next({
action: this.entity === 'group' ? 'Edited Group Users' : 'Edited Collection Users',
});
this.toasterService.popAsync('success', null, this.i18nService.t('updatedUsers'));
this.onEditedUsers.emit();
} catch { }
}
}

View File

@@ -65,7 +65,7 @@
<input type="checkbox" [(ngModel)]="c.checked" name="Collection[{{i}}].Checked" appStopProp>
</td>
<td (click)="check(c)">
<span appStopProp>{{c.name}}</span>
{{c.name}}
</td>
<td class="text-center">
<input type="checkbox" [(ngModel)]="c.readOnly" name="Collection[{{i}}].ReadOnly" [disabled]="!c.checked">

View File

@@ -131,6 +131,9 @@ export class GroupsComponent implements OnInit {
childComponent.entityId = group.id;
childComponent.entityName = group.name;
childComponent.onEditedUsers.subscribe(() => {
this.modal.close();
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});

View File

@@ -1,19 +1,19 @@
<div class="container page-content">
<div class="row">
<div class="col-3">
<div class="card">
<div class="card" *ngIf="organization">
<div class="card-header">{{'manage' | i18n}}</div>
<div class="list-group list-group-flush">
<a routerLink="people" class="list-group-item" routerLinkActive="active">
<a routerLink="people" class="list-group-item" routerLinkActive="active" *ngIf="organization.isAdmin">
{{'people' | i18n}}
</a>
<a routerLink="collections" class="list-group-item" routerLinkActive="active">
{{'collections' | i18n}}
</a>
<a routerLink="groups" class="list-group-item" routerLinkActive="active" *ngIf="accessGroups">
<a routerLink="groups" class="list-group-item" routerLinkActive="active" *ngIf="organization.isAdmin && accessGroups">
{{'groups' | i18n}}
</a>
<a routerLink="events" class="list-group-item" routerLinkActive="active" *ngIf="accessEvents">
<a routerLink="events" class="list-group-item" routerLinkActive="active" *ngIf="organization.isAdmin && accessEvents">
{{'eventLogs' | i18n}}
</a>
</div>

View File

@@ -6,11 +6,14 @@ import { ActivatedRoute } from '@angular/router';
import { UserService } from 'jslib/abstractions/user.service';
import { Organization } from 'jslib/models/domain/organization';
@Component({
selector: 'app-org-manage',
templateUrl: 'manage.component.html',
})
export class ManageComponent implements OnInit {
organization: Organization;
accessGroups = false;
accessEvents = false;
@@ -18,9 +21,9 @@ export class ManageComponent implements OnInit {
ngOnInit() {
this.route.parent.params.subscribe(async (params) => {
const organization = await this.userService.getOrganization(params.organizationId);
this.accessEvents = organization.useEvents;
this.accessGroups = organization.useGroups;
this.organization = await this.userService.getOrganization(params.organizationId);
this.accessEvents = this.organization.useEvents;
this.accessGroups = this.organization.useGroups;
});
}
}

View File

@@ -48,6 +48,7 @@
<td>
<span *ngIf="u.type === organizationUserType.Owner">{{'owner' | i18n}}</span>
<span *ngIf="u.type === organizationUserType.Admin">{{'admin' | i18n}}</span>
<span *ngIf="u.type === organizationUserType.Manager">{{'manager' | i18n}}</span>
<span *ngIf="u.type === organizationUserType.User">{{'user' | i18n}}</span>
</td>
<td class="table-list-options">
@@ -87,3 +88,4 @@
<ng-template #addEdit></ng-template>
<ng-template #groupsTemplate></ng-template>
<ng-template #eventsTemplate></ng-template>
<ng-template #confirmTemplate></ng-template>

View File

@@ -5,15 +5,21 @@ import {
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import {
ActivatedRoute,
Router,
} from '@angular/router';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { ConstantsService } from 'jslib/services/constants.service';
import { ApiService } from 'jslib/abstractions/api.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { UserService } from 'jslib/abstractions/user.service';
import { OrganizationUserConfirmRequest } from 'jslib/models/request/organizationUserConfirmRequest';
@@ -28,6 +34,7 @@ import { Utils } from 'jslib/misc/utils';
import { ModalComponent } from '../../modal.component';
import { EntityEventsComponent } from './entity-events.component';
import { UserAddEditComponent } from './user-add-edit.component';
import { UserConfirmComponent } from './user-confirm.component';
import { UserGroupsComponent } from './user-groups.component';
@Component({
@@ -38,6 +45,7 @@ export class PeopleComponent implements OnInit {
@ViewChild('addEdit', { read: ViewContainerRef }) addEditModalRef: ViewContainerRef;
@ViewChild('groupsTemplate', { read: ViewContainerRef }) groupsModalRef: ViewContainerRef;
@ViewChild('eventsTemplate', { read: ViewContainerRef }) eventsModalRef: ViewContainerRef;
@ViewChild('confirmTemplate', { read: ViewContainerRef }) confirmModalRef: ViewContainerRef;
loading = true;
organizationId: string;
@@ -58,12 +66,17 @@ export class PeopleComponent implements OnInit {
private i18nService: I18nService, private componentFactoryResolver: ComponentFactoryResolver,
private platformUtilsService: PlatformUtilsService, private analytics: Angulartics2,
private toasterService: ToasterService, private cryptoService: CryptoService,
private userService: UserService) { }
private userService: UserService, private router: Router,
private storageService: StorageService) { }
async ngOnInit() {
this.route.parent.parent.params.subscribe(async (params) => {
this.organizationId = params.organizationId;
const organization = await this.userService.getOrganization(this.organizationId);
if (!organization.isAdmin) {
this.router.navigate(['../collections'], { relativeTo: this.route });
return;
}
this.accessEvents = organization.useEvents;
this.accessGroups = organization.useGroups;
await this.load();
@@ -206,17 +219,48 @@ export class PeopleComponent implements OnInit {
}
async confirm(user: OrganizationUserUserDetailsResponse) {
function updateUser(self: PeopleComponent) {
user.status = OrganizationUserStatusType.Confirmed;
const mapIndex = self.statusMap.get(OrganizationUserStatusType.Accepted).indexOf(user);
if (mapIndex > -1) {
self.statusMap.get(OrganizationUserStatusType.Accepted).splice(mapIndex, 1);
self.statusMap.get(OrganizationUserStatusType.Confirmed).push(user);
}
}
if (this.actionPromise != null) {
return;
}
const autoConfirm = await this.storageService.get<boolean>(ConstantsService.autoConfirmFingerprints);
if (autoConfirm == null || !autoConfirm) {
if (this.modal != null) {
this.modal.close();
}
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
this.modal = this.groupsModalRef.createComponent(factory).instance;
const childComponent = this.modal.show<UserConfirmComponent>(
UserConfirmComponent, this.confirmModalRef);
childComponent.name = user != null ? user.name || user.email : null;
childComponent.organizationId = this.organizationId;
childComponent.organizationUserId = user != null ? user.id : null;
childComponent.userId = user != null ? user.userId : null;
childComponent.onConfirmedUser.subscribe(() => {
this.modal.close();
updateUser(this);
});
this.modal.onClosed.subscribe(() => {
this.modal = null;
});
return;
}
this.actionPromise = this.doConfirmation(user);
await this.actionPromise;
user.status = OrganizationUserStatusType.Confirmed;
const mapIndex = this.statusMap.get(OrganizationUserStatusType.Accepted).indexOf(user);
if (mapIndex > -1) {
this.statusMap.get(OrganizationUserStatusType.Accepted).splice(mapIndex, 1);
this.statusMap.get(OrganizationUserStatusType.Confirmed).push(user);
}
updateUser(this);
this.analytics.eventTrack.next({ action: 'Confirmed User' });
this.toasterService.popAsync('success', null, this.i18nService.t('hasBeenConfirmed', user.name || user.email));
this.actionPromise = null;
@@ -247,6 +291,11 @@ export class PeopleComponent implements OnInit {
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
const publicKeyResponse = await this.apiService.getUserPublicKey(user.userId);
const publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
try {
// tslint:disable-next-line
console.log('User\'s fingerprint: ' +
(await this.cryptoService.getFingerprint(user.userId, publicKey.buffer)).join('-'));
} catch { }
const key = await this.cryptoService.rsaEncrypt(orgKey.key, publicKey.buffer);
const request = new OrganizationUserConfirmRequest();
request.key = key.encryptedString;

View File

@@ -30,6 +30,13 @@
<small>{{'userDesc' | i18n}}</small>
</label>
</div>
<div class="form-check mt-2 form-check-block">
<input class="form-check-input" type="radio" name="userType" id="userTypeManager" [value]="organizationUserType.Manager" [(ngModel)]="type">
<label class="form-check-label" for="userTypeManager">
{{'manager' | i18n}}
<small>{{'managerDesc' | i18n}}</small>
</label>
</div>
<div class="form-check mt-2 form-check-block">
<input class="form-check-input" type="radio" name="userType" id="userTypeAdmin" [value]="organizationUserType.Admin" [(ngModel)]="type">
<label class="form-check-label" for="userTypeAdmin">
@@ -89,7 +96,7 @@
<input type="checkbox" [(ngModel)]="c.checked" name="Collection[{{i}}].Checked" appStopProp>
</td>
<td (click)="check(c)">
<span appStopProp>{{c.name}}</span>
{{c.name}}
</td>
<td class="text-center">
<input type="checkbox" [(ngModel)]="c.readOnly" name="Collection[{{i}}].ReadOnly" [disabled]="!c.checked">

View File

@@ -0,0 +1,36 @@
<div class="modal fade">
<div class="modal-dialog">
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
<div class="modal-header">
<h2 class="modal-title">
{{'confirmUser' | i18n}}
<small class="text-muted" *ngIf="name">{{name}}</small>
</h2>
<button type="button" class="close" data-dismiss="modal" attr.aria-label="{{'close' | i18n}}">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<p>
{{'fingerprintEnsureIntegrityVerify' | i18n}}
<a href="https://help.bitwarden.com/article/fingerprint-phrase/" target="_blank" rel="noopener">
{{'learnMore' | i18n}}</a>
</p>
<p><code>{{fingerprint}}</code></p>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="dontAskAgain" name="DontAskAgain" [(ngModel)]="dontAskAgain">
<label class="form-check-label" for="dontAskAgain">
{{'dontAskFingerprintAgain' | i18n}}
</label>
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}"></i>
<span>{{'confirm' | i18n}}</span>
</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'cancel' | i18n}}</button>
</div>
</form>
</div>
</div>

View File

@@ -0,0 +1,84 @@
import {
Component,
EventEmitter,
Input,
OnInit,
Output,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { ConstantsService } from 'jslib/services/constants.service';
import { ApiService } from 'jslib/abstractions/api.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { OrganizationUserConfirmRequest } from 'jslib/models/request/organizationUserConfirmRequest';
import { Utils } from 'jslib/misc/utils';
@Component({
selector: 'app-user-confirm',
templateUrl: 'user-confirm.component.html',
})
export class UserConfirmComponent implements OnInit {
@Input() name: string;
@Input() userId: string;
@Input() organizationUserId: string;
@Input() organizationId: string;
@Output() onConfirmedUser = new EventEmitter();
dontAskAgain = false;
loading = true;
fingerprint: string;
formPromise: Promise<any>;
private publicKey: Uint8Array = null;
constructor(private apiService: ApiService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService,
private cryptoService: CryptoService, private storageService: StorageService) { }
async ngOnInit() {
try {
const publicKeyResponse = await this.apiService.getUserPublicKey(this.userId);
if (publicKeyResponse != null) {
this.publicKey = Utils.fromB64ToArray(publicKeyResponse.publicKey);
const fingerprint = await this.cryptoService.getFingerprint(this.userId, this.publicKey.buffer);
if (fingerprint != null) {
this.fingerprint = fingerprint.join('-');
}
}
} catch { }
this.loading = false;
}
async submit() {
if (this.loading) {
return;
}
if (this.dontAskAgain) {
await this.storageService.save(ConstantsService.autoConfirmFingerprints, true);
}
try {
this.formPromise = this.doConfirmation();
await this.formPromise;
this.analytics.eventTrack.next({ action: 'Confirmed User' });
this.toasterService.popAsync('success', null, this.i18nService.t('hasBeenConfirmed', this.name));
this.onConfirmedUser.emit();
} catch { }
}
private async doConfirmation() {
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
const key = await this.cryptoService.rsaEncrypt(orgKey.key, this.publicKey.buffer);
const request = new OrganizationUserConfirmRequest();
request.key = key.encryptedString;
await this.apiService.postOrganizationUserConfirm(this.organizationId, this.organizationUserId, request);
}
}

View File

@@ -25,7 +25,7 @@
<input type="checkbox" [(ngModel)]="g.checked" name="Groups[{{i}}].Checked" appStopProp>
</td>
<td (click)="check(g)">
<span appStopProp>{{g.name}}</span>
{{g.name}}
</td>
</tr>
</tbody>

View File

@@ -1,11 +1,9 @@
import {
Component,
OnInit,
} from '@angular/core';
import { Component } from '@angular/core';
import { ApiService } from 'jslib/abstractions/api.service';
import { AuditService } from 'jslib/abstractions/audit.service';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
@@ -18,6 +16,7 @@ import { UserService } from 'jslib/abstractions/user.service';
import { CipherData } from 'jslib/models/data/cipherData';
import { Cipher } from 'jslib/models/domain/cipher';
import { Organization } from 'jslib/models/domain/organization';
import { CipherCreateRequest } from 'jslib/models/request/cipherCreateRequest';
import { CipherRequest } from 'jslib/models/request/cipherRequest';
import { AddEditComponent as BaseAddEditComponent } from '../../vault/add-edit.component';
@@ -26,18 +25,26 @@ import { AddEditComponent as BaseAddEditComponent } from '../../vault/add-edit.c
selector: 'app-org-vault-add-edit',
templateUrl: '../../vault/add-edit.component.html',
})
export class AddEditComponent extends BaseAddEditComponent implements OnInit {
export class AddEditComponent extends BaseAddEditComponent {
organization: Organization;
originalCipher: Cipher = null;
constructor(cipherService: CipherService, folderService: FolderService,
i18nService: I18nService, platformUtilsService: PlatformUtilsService,
auditService: AuditService, stateService: StateService,
userService: UserService, totpService: TotpService,
passwordGenerationService: PasswordGenerationService, private apiService: ApiService,
userService: UserService, collectionService: CollectionService,
totpService: TotpService, passwordGenerationService: PasswordGenerationService,
private apiService: ApiService,
messagingService: MessagingService) {
super(cipherService, folderService, i18nService, platformUtilsService, auditService, stateService,
userService, totpService, passwordGenerationService, messagingService);
userService, collectionService, totpService, passwordGenerationService, messagingService);
}
protected loadCollections() {
if (!this.organization.isAdmin) {
return super.loadCollections();
}
return Promise.resolve(this.collections);
}
protected async loadCipher() {
@@ -51,9 +58,6 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
}
protected encryptCipher() {
if (!this.editMode) {
this.cipher.organizationId = this.organization.id;
}
if (!this.organization.isAdmin) {
return super.encryptCipher();
}
@@ -64,10 +68,11 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
if (!this.organization.isAdmin) {
return super.saveCipher(cipher);
}
const request = new CipherRequest(cipher);
if (this.editMode) {
const request = new CipherRequest(cipher);
return this.apiService.putCipherAdmin(this.cipherId, request);
} else {
const request = new CipherCreateRequest(cipher);
return this.apiService.postCipherAdmin(request);
}
}

View File

@@ -11,6 +11,8 @@ import { CipherData } from 'jslib/models/data/cipherData';
import { Cipher } from 'jslib/models/domain/cipher';
import { Organization } from 'jslib/models/domain/organization';
import { AttachmentView } from 'jslib/models/view/attachmentView';
import { AttachmentsComponent as BaseAttachmentsComponent } from '../../vault/attachments.component';
@Component({
@@ -26,6 +28,12 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
super(cipherService, i18nService, cryptoService, userService, platformUtilsService);
}
protected async reupload(attachment: AttachmentView) {
if (this.organization.isAdmin && this.showFixOldAttachments(attachment)) {
await super.reuploadCipherAttachment(attachment, true);
}
}
protected async loadCipher() {
if (!this.organization.isAdmin) {
return await super.loadCipher();
@@ -44,4 +52,8 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
}
return this.apiService.deleteCipherAttachmentAdmin(this.cipherId, attachmentId);
}
protected showFixOldAttachments(attachment: AttachmentView) {
return attachment.key == null && this.organization.isAdmin;
}
}

View File

@@ -41,7 +41,7 @@ export class CiphersComponent extends BaseCiphersComponent {
async load(filter: (cipher: CipherView) => boolean = null) {
if (!this.organization.isAdmin) {
await super.load();
await super.load(filter);
return;
}
this.accessEvents = this.organization.useEvents;
@@ -103,4 +103,8 @@ export class CiphersComponent extends BaseCiphersComponent {
}
return this.apiService.deleteCipherAdmin(id);
}
protected showFixOldAttachments(c: CipherView) {
return this.organization.isAdmin && c.hasOldAttachments;
}
}

View File

@@ -1,12 +1,10 @@
import { Component } from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { ApiService } from 'jslib/abstractions/api.service';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { CipherData } from 'jslib/models/data/cipherData';
import { Cipher } from 'jslib/models/domain/cipher';
@@ -22,10 +20,10 @@ import { CollectionsComponent as BaseCollectionsComponent } from '../../vault/co
export class CollectionsComponent extends BaseCollectionsComponent {
organization: Organization;
constructor(collectionService: CollectionService, analytics: Angulartics2,
toasterService: ToasterService, i18nService: I18nService,
cipherService: CipherService, private apiService: ApiService) {
super(collectionService, analytics, toasterService, i18nService, cipherService);
constructor(collectionService: CollectionService, platformUtilsService: PlatformUtilsService,
i18nService: I18nService, cipherService: CipherService,
private apiService: ApiService) {
super(collectionService, platformUtilsService, i18nService, cipherService);
}
protected async loadCipher() {

View File

@@ -4,6 +4,8 @@ import { ApiService } from 'jslib/abstractions/api.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { UserService } from 'jslib/abstractions/user.service';
import { CollectionData } from 'jslib/models/data/collectionData';
import { Collection } from 'jslib/models/domain/collection';
@@ -21,8 +23,9 @@ export class GroupingsComponent extends BaseGroupingsComponent {
organization: Organization;
constructor(collectionService: CollectionService, folderService: FolderService,
storageService: StorageService, userService: UserService,
private apiService: ApiService, private i18nService: I18nService) {
super(collectionService, folderService);
super(collectionService, folderService, storageService, userService);
}
async loadCollections() {
@@ -30,6 +33,7 @@ export class GroupingsComponent extends BaseGroupingsComponent {
await super.loadCollections(this.organization.id);
return;
}
const collections = await this.apiService.getCollections(this.organization.id);
if (collections != null && collections.data != null && collections.data.length) {
const collectionDomains = collections.data.map((r) =>
@@ -45,5 +49,14 @@ export class GroupingsComponent extends BaseGroupingsComponent {
unassignedCollection.organizationId = this.organization.id;
unassignedCollection.readOnly = true;
this.collections.push(unassignedCollection);
this.nestedCollections = await this.collectionService.getAllNested(this.collections);
}
collapse(grouping: CollectionView) {
super.collapse(grouping, 'org_');
}
isCollapsed(grouping: CollectionView) {
return super.isCollapsed(grouping, 'org_');
}
}

View File

@@ -13,7 +13,7 @@
<i *ngIf="actionSpinner.loading" class="fa fa-spinner fa-spin text-muted" title="{{'loading' | i18n}}"></i>
</small>
</h1>
<button type="button" class="btn btn-outline-primary btn-sm ml-auto" (click)="addCipher()" *ngIf="showAdd">
<button type="button" class="btn btn-outline-primary btn-sm ml-auto" (click)="addCipher()">
<i class="fa fa-plus fa-fw"></i>{{'addItem' | i18n}}
</button>
</div>

View File

@@ -52,7 +52,6 @@ export class VaultComponent implements OnInit, OnDestroy {
organization: Organization;
collectionId: string;
type: CipherType;
showAdd = true;
private modal: ModalComponent = null;
@@ -66,7 +65,6 @@ export class VaultComponent implements OnInit, OnDestroy {
ngOnInit() {
this.route.parent.params.subscribe(async (params) => {
this.organization = await this.userService.getOrganization(params.organizationId);
this.showAdd = this.organization.isAdmin;
this.groupingsComponent.organization = this.organization;
this.ciphersComponent.organization = this.organization;
@@ -146,7 +144,7 @@ export class VaultComponent implements OnInit, OnDestroy {
}
async filterCollection(collectionId: string, load = false) {
this.ciphersComponent.showAddNew = false;
this.ciphersComponent.showAddNew = true;
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchCollection');
const filter = (c: CipherView) => {
if (collectionId === 'unassigned') {
@@ -226,7 +224,14 @@ export class VaultComponent implements OnInit, OnDestroy {
addCipher() {
const component = this.editCipher(null);
component.organizationId = this.organization.id;
component.type = this.type;
if (this.organization.isAdmin) {
component.collections = this.groupingsComponent.collections.filter((c) => !c.readOnly);
}
if (this.collectionId != null) {
component.collectionIds = [this.collectionId];
}
}
editCipher(cipher: CipherView) {

View File

@@ -4,8 +4,8 @@
<div class="col-6">
<div class="form-group">
<label for="currentMasterPassword">{{'currentMasterPass' | i18n}}</label>
<input id="currentMasterPassword" type="password" name="MasterPasswordHash" class="form-control" [(ngModel)]="currentMasterPassword"
required appInputVerbatim>
<input id="currentMasterPassword" type="password" name="MasterPasswordHash" class="form-control"
[(ngModel)]="currentMasterPassword" required appInputVerbatim>
</div>
</div>
</div>
@@ -13,18 +13,33 @@
<div class="col-6">
<div class="form-group">
<label for="newMasterPassword">{{'newMasterPass' | i18n}}</label>
<input id="newMasterPassword" type="password" name="NewMasterPasswordHash" class="form-control" [(ngModel)]="newMasterPassword"
required appInputVerbatim autocomplete="new-password">
<input id="newMasterPassword" type="password" name="NewMasterPasswordHash" class="form-control mb-1"
[(ngModel)]="newMasterPassword" (input)="updatePasswordStrength()" required appInputVerbatim
autocomplete="new-password">
<app-password-strength [score]="masterPasswordScore" [showText]="true"></app-password-strength>
</div>
</div>
<div class="col-6">
<div class="form-group">
<label for="confirmNewMasterPassword">{{'confirmNewMasterPass' | i18n}}</label>
<input id="confirmNewMasterPassword" type="password" name="ConfirmNewMasterPasswordHash" class="form-control" [(ngModel)]="confirmNewMasterPassword"
required appInputVerbatim autocomplete="new-password">
<input id="confirmNewMasterPassword" type="password" name="ConfirmNewMasterPasswordHash" class="form-control"
[(ngModel)]="confirmNewMasterPassword" required appInputVerbatim autocomplete="new-password">
</div>
</div>
</div>
<div class="form-group">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="rotateEncKey" name="RotateEncKey" [(ngModel)]="rotateEncKey"
(change)="rotateEncKeyClicked()">
<label class="form-check-label" for="rotateEncKey">
{{'rotateAccountEncKey' | i18n}}
</label>
<a href="https://help.bitwarden.com/article/change-your-master-password/#rotating-your-accounts-encryption-key"
target="_blank" rel="noopener" title="{{'learnMore' | i18n}}">
<i class="fa fa-question-circle-o"></i>
</a>
</div>
</div>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}"></i>
<span>{{'changeMasterPassword' | i18n}}</span>

View File

@@ -1,31 +1,55 @@
import {
Component,
OnInit,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { ApiService } from 'jslib/abstractions/api.service';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { SyncService } from 'jslib/abstractions/sync.service';
import { UserService } from 'jslib/abstractions/user.service';
import { CipherString } from 'jslib/models/domain/cipherString';
import { SymmetricCryptoKey } from 'jslib/models/domain/symmetricCryptoKey';
import { CipherWithIdRequest } from 'jslib/models/request/cipherWithIdRequest';
import { FolderWithIdRequest } from 'jslib/models/request/folderWithIdRequest';
import { PasswordRequest } from 'jslib/models/request/passwordRequest';
import { UpdateKeyRequest } from 'jslib/models/request/updateKeyRequest';
@Component({
selector: 'app-change-password',
templateUrl: 'change-password.component.html',
})
export class ChangePasswordComponent {
export class ChangePasswordComponent implements OnInit {
currentMasterPassword: string;
newMasterPassword: string;
confirmNewMasterPassword: string;
formPromise: Promise<any>;
masterPasswordScore: number;
rotateEncKey = false;
private masterPasswordStrengthTimeout: any;
private email: string;
constructor(private apiService: ApiService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService,
private cryptoService: CryptoService, private messagingService: MessagingService,
private userService: UserService) { }
private userService: UserService, private passwordGenerationService: PasswordGenerationService,
private platformUtilsService: PlatformUtilsService, private folderService: FolderService,
private cipherService: CipherService, private syncService: SyncService) { }
async ngOnInit() {
this.email = await this.userService.getEmail();
}
async submit() {
const hasEncKey = await this.cryptoService.hasEncKey();
@@ -51,6 +75,21 @@ export class ChangePasswordComponent {
return;
}
const strengthResult = this.passwordGenerationService.passwordStrength(this.newMasterPassword,
this.getPasswordStrengthUserInput());
if (strengthResult != null && strengthResult.score < 3) {
const result = await this.platformUtilsService.showDialog(this.i18nService.t('weakMasterPasswordDesc'),
this.i18nService.t('weakMasterPassword'), this.i18nService.t('yes'), this.i18nService.t('no'),
'warning');
if (!result) {
return;
}
}
if (this.rotateEncKey) {
await this.syncService.fullSync(true);
}
const request = new PasswordRequest();
request.masterPasswordHash = await this.cryptoService.hashPassword(this.currentMasterPassword, null);
const email = await this.userService.getEmail();
@@ -61,7 +100,13 @@ export class ChangePasswordComponent {
const newEncKey = await this.cryptoService.remakeEncKey(newKey);
request.key = newEncKey[1].encryptedString;
try {
this.formPromise = this.apiService.postPassword(request);
if (this.rotateEncKey) {
this.formPromise = this.apiService.postPassword(request).then(() => {
return this.updateKey(newKey, request.newMasterPasswordHash);
});
} else {
this.formPromise = this.apiService.postPassword(request);
}
await this.formPromise;
this.analytics.eventTrack.next({ action: 'Changed Password' });
this.toasterService.popAsync('success', this.i18nService.t('masterPasswordChanged'),
@@ -69,4 +114,93 @@ export class ChangePasswordComponent {
this.messagingService.send('logout');
} catch { }
}
updatePasswordStrength() {
if (this.masterPasswordStrengthTimeout != null) {
clearTimeout(this.masterPasswordStrengthTimeout);
}
this.masterPasswordStrengthTimeout = setTimeout(() => {
const strengthResult = this.passwordGenerationService.passwordStrength(this.newMasterPassword,
this.getPasswordStrengthUserInput());
this.masterPasswordScore = strengthResult == null ? null : strengthResult.score;
}, 300);
}
async rotateEncKeyClicked() {
if (this.rotateEncKey) {
const ciphers = await this.cipherService.getAllDecrypted();
let hasOldAttachments = false;
if (ciphers != null) {
for (let i = 0; i < ciphers.length; i++) {
if (ciphers[i].organizationId == null && ciphers[i].hasOldAttachments) {
hasOldAttachments = true;
break;
}
}
}
if (hasOldAttachments) {
const learnMore = await this.platformUtilsService.showDialog(
this.i18nService.t('oldAttachmentsNeedFixDesc'), null,
this.i18nService.t('learnMore'), this.i18nService.t('close'), 'warning');
if (learnMore) {
this.platformUtilsService.launchUri(
'https://help.bitwarden.com/article/attachments/#fixing-old-attachments');
}
this.rotateEncKey = false;
return;
}
const result = await this.platformUtilsService.showDialog(
this.i18nService.t('updateEncryptionKeyWarning') + ' ' +
this.i18nService.t('rotateEncKeyConfirmation'), this.i18nService.t('rotateEncKeyTitle'),
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
if (!result) {
this.rotateEncKey = false;
}
}
}
private getPasswordStrengthUserInput() {
let userInput: string[] = [];
const atPosition = this.email.indexOf('@');
if (atPosition > -1) {
userInput = userInput.concat(this.email.substr(0, atPosition).trim().toLowerCase().split(/[^A-Za-z0-9]/));
}
return userInput;
}
private async updateKey(key: SymmetricCryptoKey, masterPasswordHash: string) {
const encKey = await this.cryptoService.makeEncKey(key);
const privateKey = await this.cryptoService.getPrivateKey();
let encPrivateKey: CipherString = null;
if (privateKey != null) {
encPrivateKey = await this.cryptoService.encrypt(privateKey, encKey[0]);
}
const request = new UpdateKeyRequest();
request.privateKey = encPrivateKey != null ? encPrivateKey.encryptedString : null;
request.key = encKey[1].encryptedString;
request.masterPasswordHash = masterPasswordHash;
const folders = await this.folderService.getAllDecrypted();
for (let i = 0; i < folders.length; i++) {
if (folders[i].id == null) {
continue;
}
const folder = await this.folderService.encrypt(folders[i], encKey[0]);
request.folders.push(new FolderWithIdRequest(folder));
}
const ciphers = await this.cipherService.getAllDecrypted();
for (let i = 0; i < ciphers.length; i++) {
if (ciphers[i].organizationId != null) {
continue;
}
const cipher = await this.cipherService.encrypt(ciphers[i], encKey[0]);
request.ciphers.push(new CipherWithIdRequest(cipher));
}
await this.apiService.postAccountKey(request);
}
}

View File

@@ -121,7 +121,16 @@
<label for="additionalStorage">{{'additionalStorageGb' | i18n}}</label>
<input id="additionalStorage" class="form-control" type="number" name="AdditionalStorageGb" [(ngModel)]="additionalStorage"
min="0" max="99" step="1" placeholder="{{'additionalStorageGbDesc' | i18n}}">
<small class="text-muted form-text">{{'additionalStorageDesc' | i18n : '1 GB' : (storageGb.price | currency:'$')}}</small>
<small class="text-muted form-text">{{'additionalStorageIntervalDesc' | i18n : '1 GB' : (storageGb.price | currency:'$') : ('month' | i18n)}}</small>
</div>
</div>
<div class="row">
<div class="form-group col-6" *ngIf="plans[plan].canBuyPremiumAccessAddon">
<div class="form-check">
<input id="premiumAccess" class="form-check-input" type="checkbox" name="PremiumAccessAddon" [(ngModel)]="premiumAccessAddon">
<label for="premiumAccess" class="form-check-label bold">{{'premiumAccess' | i18n}}</label>
</div>
<small class="text-muted form-text">{{'premiumAccessDesc' | i18n : (3.33 | currency:'$') : ('month' | i18n)}}</small>
</div>
</div>
<h2 class="spaced-header">{{'summary' | i18n}}</h2>
@@ -143,6 +152,10 @@
{{'additionalStorageGb' | i18n}}: {{additionalStorage || 0}} &times; {{storageGb.price | currency:'$'}} &times;12 {{'monthAbbr'
| i18n}} = {{additionalStorageTotal(true) | currency:'$'}} /{{'year' | i18n}}
</small>
<small *ngIf="plans[plan].canBuyPremiumAccessAddon && premiumAccessAddon">
{{'premiumAccess' | i18n}}:
{{3.33 | currency:'$'}} &times;12 {{'monthAbbr' | i18n}} = {{40 | currency:'$'}} /{{'year' | i18n}}
</small>
</label>
</div>
<div class="form-check form-check-block" *ngIf="plans[plan].monthlySeatPrice">

View File

@@ -31,6 +31,7 @@ export class CreateOrganizationComponent implements OnInit {
selfHosted = false;
ownedBusiness = false;
premiumAccessAddon = false;
storageGbPriceMonthly = 0.33;
additionalStorage = 0;
additionalSeats = 0;
@@ -58,6 +59,7 @@ export class CreateOrganizationComponent implements OnInit {
baseSeats: 5,
noAdditionalSeats: true,
annualPlanType: PlanType.FamiliesAnnually,
canBuyPremiumAccessAddon: true,
},
teams: {
basePrice: 5,
@@ -144,6 +146,8 @@ export class CreateOrganizationComponent implements OnInit {
request.businessName = this.ownedBusiness ? this.businessName : null;
request.additionalSeats = this.additionalSeats;
request.additionalStorageGb = this.additionalStorage;
request.premiumAccessAddon = this.plans[this.plan].canBuyPremiumAccessAddon &&
this.premiumAccessAddon;
request.country = this.paymentComponent.getCountry();
if (this.interval === 'month') {
request.planType = this.plans[this.plan].monthPlanType;
@@ -170,6 +174,10 @@ export class CreateOrganizationComponent implements OnInit {
}
changedPlan() {
if (!this.plans[this.plan].canBuyPremiumAccessAddon) {
this.premiumAccessAddon = false;
}
if (this.plans[this.plan].monthPlanType == null) {
this.interval = 'year';
}
@@ -217,8 +225,18 @@ export class CreateOrganizationComponent implements OnInit {
}
}
premiumAccessTotal(annual: boolean): number {
if (this.plans[this.plan].canBuyPremiumAccessAddon && this.premiumAccessAddon) {
if (annual) {
return 40;
}
}
return 0;
}
get total(): number {
const annual = this.interval === 'year';
return this.baseTotal(annual) + this.seatTotal(annual) + this.additionalStorageTotal(annual);
return this.baseTotal(annual) + this.seatTotal(annual) + this.additionalStorageTotal(annual) +
this.premiumAccessTotal(annual);
}
}

View File

@@ -55,7 +55,7 @@
<label for="additionalStorage">{{'additionalStorageGb' | i18n}}</label>
<input id="additionalStorage" class="form-control" type="number" name="AdditionalStorageGb" [(ngModel)]="additionalStorage"
min="0" max="99" step="1" placeholder="{{'additionalStorageGbDesc' | i18n}}">
<small class="text-muted form-text">{{'additionalStorageDesc' | i18n : '1 GB' : (storageGbPrice | currency:'$')}}</small>
<small class="text-muted form-text">{{'additionalStorageIntervalDesc' | i18n : '1 GB' : (storageGbPrice | currency:'$') : ('year' | i18n)}}</small>
</div>
</div>
<h2 class="spaced-header">{{'summary' | i18n}}</h2>

View File

@@ -18,7 +18,17 @@
</div>
</div>
<div class="col-6">
<app-avatar data="{{profile.name || profile.email}}" [email]="profile.email" dynamic="true" size="75" fontSize="35"></app-avatar>
<div class="mb-3">
<app-avatar data="{{profile.name || profile.email}}" [email]="profile.email" dynamic="true" size="75"
fontSize="35"></app-avatar>
</div>
<hr>
<p *ngIf="fingerprint">
{{'yourAccountsFingerprint' | i18n}}:
<a href="https://help.bitwarden.com/article/fingerprint-phrase/" target="_blank" rel="noopener" title="{{'learnMore' | i18n}}">
<i class="fa fa-question-circle-o"></i></a><br>
<code>{{fingerprint}}</code>
</p>
</div>
</div>
<button type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">

View File

@@ -7,7 +7,9 @@ import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { ApiService } from 'jslib/abstractions/api.service';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { UserService } from 'jslib/abstractions/user.service';
import { UpdateProfileRequest } from 'jslib/models/request/updateProfileRequest';
@@ -20,15 +22,21 @@ import { ProfileResponse } from 'jslib/models/response/profileResponse';
export class ProfileComponent implements OnInit {
loading = true;
profile: ProfileResponse;
fingerprint: string;
formPromise: Promise<any>;
constructor(private apiService: ApiService, private i18nService: I18nService,
private analytics: Angulartics2, private toasterService: ToasterService) { }
private analytics: Angulartics2, private toasterService: ToasterService,
private userService: UserService, private cryptoService: CryptoService) { }
async ngOnInit() {
this.profile = await this.apiService.getProfile();
this.loading = false;
const fingerprint = await this.cryptoService.getFingerprint(await this.userService.getUserId());
if (fingerprint != null) {
this.fingerprint = fingerprint.join('-');
}
}
async submit() {

View File

@@ -83,7 +83,7 @@
<a href="#" appStopClick class="badge badge-primary ml-3" (click)="premiumRequired()" *ngIf="!organization && !cipher.organizationId && !canAccessPremium">
{{'premium' | i18n}}
</a>
<a href="#" appStopClick class="badge badge-primary ml-3" (click)="upgradeOrganization()" *ngIf="(organization && !organization.useTotp) || (cipher.organizationId && !cipher.organizationUseTotp)">
<a href="#" appStopClick class="badge badge-primary ml-3" (click)="upgradeOrganization()" *ngIf="(organization && !organization.useTotp) || (!organization && !canAccessPremium && cipher.organizationId && !cipher.organizationUseTotp)">
{{'upgrade' | i18n}}
</a>
</div>
@@ -366,6 +366,30 @@
</select>
</div>
</div>
<ng-container *ngIf="!editMode && !organization && ownershipOptions && ownershipOptions.length > 1">
<h3 class="mt-4">{{'ownership' | i18n}}</h3>
<div class="row">
<div class="col-5">
<label for="organizationId">{{'whoOwnsThisItem' | i18n}}</label>
<select id="organizationId" class="form-control" name="OrganizationId" [(ngModel)]="cipher.organizationId"
(change)="organizationChanged()">
<option *ngFor="let o of ownershipOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
</div>
</ng-container>
<ng-container *ngIf="!editMode && cipher.organizationId">
<h3 class="mt-4">{{'collections' | i18n}}</h3>
<div *ngIf="!collections || !collections.length">
{{'noCollectionsInList' | i18n}}
</div>
<ng-container *ngIf="collections && collections.length">
<div class="form-check" *ngFor="let c of collections; let i = index">
<input class="form-check-input" type="checkbox" [(ngModel)]="c.checked" id="collection-{{i}}" name="Collection[{{i}}].Checked">
<label class="form-check-label" for="collection-{{i}}">{{c.name}}</label>
</div>
</ng-container>
</ng-container>
<ng-container *ngIf="editMode">
<div class="small text-muted mt-4">
<div>

View File

@@ -1,12 +1,10 @@
import {
Component,
OnInit,
} from '@angular/core';
import { Component } from '@angular/core';
import { CipherType } from 'jslib/enums/cipherType';
import { AuditService } from 'jslib/abstractions/audit.service';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
@@ -23,7 +21,7 @@ import { LoginUriView } from 'jslib/models/view/loginUriView';
selector: 'app-vault-add-edit',
templateUrl: 'add-edit.component.html',
})
export class AddEditComponent extends BaseAddEditComponent implements OnInit {
export class AddEditComponent extends BaseAddEditComponent {
canAccessPremium: boolean;
totpCode: string;
totpCodeFormatted: string;
@@ -39,13 +37,16 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit {
constructor(cipherService: CipherService, folderService: FolderService,
i18nService: I18nService, platformUtilsService: PlatformUtilsService,
auditService: AuditService, stateService: StateService,
protected userService: UserService, protected totpService: TotpService,
protected passwordGenerationService: PasswordGenerationService, protected messagingService: MessagingService) {
super(cipherService, folderService, i18nService, platformUtilsService, auditService, stateService);
userService: UserService, collectionService: CollectionService,
protected totpService: TotpService, protected passwordGenerationService: PasswordGenerationService,
protected messagingService: MessagingService) {
super(cipherService, folderService, i18nService, platformUtilsService, auditService, stateService,
userService, collectionService);
}
async ngOnInit() {
await super.load();
await super.ngOnInit();
await this.load();
this.showRevisionDate = this.cipher.passwordRevisionDisplayDate != null;
this.hasPasswordHistory = this.cipher.hasPasswordHistory;
this.cleanUp();

View File

@@ -19,13 +19,22 @@
<i class="fa fa-spinner fa-lg fa-fw fa-spin" *ngIf="a.downloading"></i>
</td>
<td>
<a href="#" appStopClick (click)="download(a)">{{a.fileName}}</a>
<br>
<div class="d-flex">
<a href="#" appStopClick (click)="download(a)">{{a.fileName}}</a>
<div *ngIf="showFixOldAttachments(a)" class="ml-2">
<a href="https://help.bitwarden.com/article/attachments/#fixing-old-attachments"
target="_blank" rel="noopener">
<i class="fa fa-exclamation-triangle text-warning" title="{{'attachmentFixDesc' | i18n}}"></i></a>
<button type="button" class="btn btn-outline-primary btn-sm m-0 py-0 px-2"
(click)="reupload(a)" #reuploadBtn [appApiAction]="reuploadPromises[a.id]"
[disabled]="reuploadBtn.loading">{{'fix' | i18n}}</button>
</div>
</div>
<small>{{a.sizeName}}</small>
</td>
<td class="table-list-options">
<button class="btn btn-outline-danger" type="button" appStopClick title="{{'delete' | i18n}}" (click)="delete(a)" #deleteBtn
[appApiAction]="deletePromises[a.id]" [disabled]="deleteBtn.loading">
<button class="btn btn-outline-danger" type="button" appStopClick title="{{'delete' | i18n}}"
(click)="delete(a)" #deleteBtn [appApiAction]="deletePromises[a.id]" [disabled]="deleteBtn.loading">
<i class="fa fa-trash-o fa-lg fa-fw" [hidden]="deleteBtn.loading"></i>
<i class="fa fa-spinner fa-spin fa-lg fa-fw" [hidden]="!deleteBtn.loading" title="{{'loading' | i18n}}"></i>
</button>
@@ -43,7 +52,8 @@
<i class="fa fa-spinner fa-spin" title="{{'loading' | i18n}}"></i>
<span>{{'save' | i18n}}</span>
</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal" title="{{'close' | i18n}}">{{'close' | i18n}}</button>
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal" title="{{'close' | i18n}}">{{'close'
| i18n}}</button>
</div>
</form>
</div>

View File

@@ -6,6 +6,8 @@ import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { UserService } from 'jslib/abstractions/user.service';
import { AttachmentView } from 'jslib/models/view/attachmentView';
import { AttachmentsComponent as BaseAttachmentsComponent } from 'jslib/angular/components/attachments.component';
@Component({
@@ -18,4 +20,14 @@ export class AttachmentsComponent extends BaseAttachmentsComponent {
platformUtilsService: PlatformUtilsService) {
super(cipherService, i18nService, cryptoService, userService, platformUtilsService, window);
}
protected async reupload(attachment: AttachmentView) {
if (this.showFixOldAttachments(attachment)) {
await this.reuploadCipherAttachment(attachment, false);
}
}
protected showFixOldAttachments(attachment: AttachmentView) {
return attachment.key == null && this.cipher.organizationId == null;
}
}

View File

@@ -11,7 +11,7 @@
</div>
<div class="modal-body">
<p>{{'shareManyDesc' | i18n}}</p>
<p>{{'shareSelectedItemsDesc' | i18n: this.ciphers.length : shareableCiphers.length : nonShareableCount}}</p>
<p>{{'shareSelectedItemsCountDesc' | i18n: this.ciphers.length : shareableCiphers.length : nonShareableCount}}</p>
<div class="form-group">
<label for="organization">{{'organization' | i18n}}</label>
<select id="organization" name="OrganizationId" [(ngModel)]="organizationId" class="form-control" (change)="filterCollections()">
@@ -39,7 +39,7 @@
<input type="checkbox" [(ngModel)]="c.checked" name="Collection[{{i}}].Checked" appStopProp>
</td>
<td>
<span appStopProp>{{c.name}}</span>
{{c.name}}
</td>
</tr>
</tbody>

View File

@@ -41,7 +41,7 @@ export class BulkShareComponent implements OnInit {
private collectionService: CollectionService, private userService: UserService) { }
async ngOnInit() {
this.shareableCiphers = this.ciphers.filter((c) => !c.hasAttachments && c.organizationId == null);
this.shareableCiphers = this.ciphers.filter((c) => !c.hasOldAttachments && c.organizationId == null);
this.nonShareableCount = this.ciphers.length - this.shareableCiphers.length;
const allCollections = await this.collectionService.getAllDecrypted();
this.writeableCollections = allCollections.filter((c) => !c.readOnly);

View File

@@ -11,7 +11,11 @@
<td (click)="checkCipher(c)" class="reduced-lh wrap">
<a href="#" appStopClick appStopProp (click)="selectCipher(c)" title="{{'editItem' | i18n}}">{{c.name}}</a>
<i class="fa fa-share-alt" appStopProp *ngIf="!organization && c.organizationId" title="{{'shared' | i18n}}"></i>
<i class="fa fa-paperclip" appStopProp *ngIf="c.hasAttachments" title="{{'attachments' | i18n}}"></i>
<ng-container *ngIf="c.hasAttachments">
<i class="fa fa-paperclip" appStopProp title="{{'attachments' | i18n}}"></i>
<i class="fa fa-exclamation-triangle text-warning" appStopProp *ngIf="showFixOldAttachments(c)"
title="{{'attachmentsNeedFix' | i18n}}"></i>
</ng-container>
<br>
<small appStopProp>{{c.subTitle}}</small>
</td>

View File

@@ -127,4 +127,8 @@ export class CiphersComponent extends BaseCiphersComponent implements OnDestroy
protected deleteCipher(id: string) {
return this.cipherService.deleteWithServer(id);
}
protected showFixOldAttachments(c: CipherView) {
return c.hasOldAttachments && c.organizationId == null;
}
}

View File

@@ -33,7 +33,7 @@
<input type="checkbox" [(ngModel)]="c.checked" name="Collection[{{i}}].Checked" appStopProp>
</td>
<td>
<span appStopProp>{{c.name}}</span>
{{c.name}}
</td>
</tr>
</tbody>

View File

@@ -1,72 +1,31 @@
import {
Component,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { CipherView } from 'jslib/models/view/cipherView';
import { CollectionView } from 'jslib/models/view/collectionView';
import { Cipher } from 'jslib/models/domain/cipher';
import { CollectionsComponent as BaseCollectionsComponent } from 'jslib/angular/components/collections.component';
@Component({
selector: 'app-vault-collections',
templateUrl: 'collections.component.html',
})
export class CollectionsComponent implements OnInit, OnDestroy {
@Input() cipherId: string;
@Output() onSavedCollections = new EventEmitter();
formPromise: Promise<any>;
cipher: CipherView;
collectionIds: string[];
collections: CollectionView[] = [];
protected cipherDomain: Cipher;
constructor(protected collectionService: CollectionService, protected analytics: Angulartics2,
protected toasterService: ToasterService, protected i18nService: I18nService,
protected cipherService: CipherService) { }
async ngOnInit() {
this.cipherDomain = await this.loadCipher();
this.collectionIds = this.loadCipherCollections();
this.cipher = await this.cipherDomain.decrypt();
this.collections = await this.loadCollections();
this.selectAll(false);
if (this.collectionIds != null) {
this.collections.forEach((c) => {
(c as any).checked = this.collectionIds != null && this.collectionIds.indexOf(c.id) > -1;
});
}
export class CollectionsComponent extends BaseCollectionsComponent implements OnDestroy {
constructor(collectionService: CollectionService, platformUtilsService: PlatformUtilsService,
i18nService: I18nService, cipherService: CipherService) {
super(collectionService, platformUtilsService, i18nService, cipherService);
}
ngOnDestroy() {
this.selectAll(false);
}
async submit() {
this.cipherDomain.collectionIds = this.collections
.filter((c) => !!(c as any).checked)
.map((c) => c.id);
this.formPromise = this.saveCollections();
await this.formPromise;
this.onSavedCollections.emit();
this.analytics.eventTrack.next({ action: 'Edited Cipher Collections' });
this.toasterService.popAsync('success', null, this.i18nService.t('editedItem'));
}
check(c: CollectionView, select?: boolean) {
(c as any).checked = select == null ? !(c as any).checked : select;
}
@@ -74,21 +33,4 @@ export class CollectionsComponent implements OnInit, OnDestroy {
selectAll(select: boolean) {
this.collections.forEach((c) => this.check(c, select));
}
protected loadCipher() {
return this.cipherService.get(this.cipherId);
}
protected loadCipherCollections() {
return this.cipherDomain.collectionIds;
}
protected async loadCollections() {
const allCollections = await this.collectionService.getAllDecrypted();
return allCollections.filter((c) => !c.readOnly && c.organizationId === this.cipher.organizationId);
}
protected saveCollections() {
return this.cipherService.saveCollectionsWithServer(this.cipherDomain);
}
}

View File

@@ -3,8 +3,8 @@
{{'filters' | i18n}}
</div>
<div class="card-body">
<input type="search" placeholder="{{searchPlaceholder || ('searchVault' | i18n)}}" id="search" class="form-control" [(ngModel)]="searchText"
(input)="searchTextChanged()" appAutofocus>
<input type="search" placeholder="{{searchPlaceholder || ('searchVault' | i18n)}}" id="search" class="form-control"
[(ngModel)]="searchText" (input)="searchTextChanged()" appAutofocus>
<ul class="fa-ul card-ul">
<li [ngClass]="{active: selectedAll}">
<a href="#" appStopClick (click)="selectAll()">
@@ -52,22 +52,37 @@
</a>
</h3>
<ul class="fa-ul card-ul carets">
<li *ngFor="let f of folders" class="d-flex" [ngClass]="{active: selectedFolder && f.id === selectedFolderId}">
<a href="#" appStopClick (click)="selectFolder(f)">
<i class="fa-li fa fa-caret-right"></i> {{f.name}}</a>
<a href="#" class="text-muted ml-auto show-active" appStopClick (click)="editFolder(f)" title="{{'editFolder' | i18n}}" *ngIf="f.id">
<i class="fa fa-pencil fa-fw"></i>
</a>
</li>
<ng-template #recursiveFolders let-folders>
<li *ngFor="let f of folders" [ngClass]="{active: selectedFolder && f.node.id === selectedFolderId}">
<div class="d-flex">
<i class="fa-li fa" title="{{'toggleCollapse' | i18n}}" [ngClass]="{'fa-caret-right': isCollapsed(f.node), 'fa-caret-down': !isCollapsed(f.node)}" (click)="collapse(f.node)"></i>
<a href="#" appStopClick (click)="selectFolder(f.node)">{{f.node.name}}</a>
<a href="#" class="text-muted ml-auto show-active" appStopClick (click)="editFolder(f.node)"
title="{{'editFolder' | i18n}}" *ngIf="f.node.id">
<i class="fa fa-pencil fa-fw"></i>
</a>
</div>
<ul class="fa-ul card-ul carets" *ngIf="f.children.length && !isCollapsed(f.node)">
<ng-container *ngTemplateOutlet="recursiveFolders; context:{ $implicit: f.children }"></ng-container>
</ul>
</li>
</ng-template>
<ng-container *ngTemplateOutlet="recursiveFolders; context:{ $implicit: nestedFolders }"></ng-container>
</ul>
</ng-container>
<ng-container *ngIf="showCollections && collections && collections.length">
<h3>{{'collections' | i18n}}</h3>
<ul class="fa-ul card-ul carets">
<li *ngFor="let c of collections" [ngClass]="{active: c.id === selectedCollectionId}">
<a href="#" appStopClick (click)="selectCollection(c)">
<i class="fa-li fa fa-caret-right"></i> {{c.name}}</a>
</li>
<ng-template #recursiveCollections let-collections>
<li *ngFor="let c of collections" [ngClass]="{active: c.node.id === selectedCollectionId}">
<i class="fa-li fa" title="{{'toggleCollapse' | i18n}}" [ngClass]="{'fa-caret-right': isCollapsed(c.node), 'fa-caret-down': !isCollapsed(c.node)}" (click)="collapse(c.node)"></i>
<a href="#" appStopClick (click)="selectCollection(c.node)">{{c.node.name}}</a>
<ul class="fa-ul card-ul carets" *ngIf="c.children.length && !isCollapsed(c.node)">
<ng-container *ngTemplateOutlet="recursiveCollections; context:{ $implicit: c.children }"></ng-container>
</ul>
</li>
</ng-template>
<ng-container *ngTemplateOutlet="recursiveCollections; context:{ $implicit: nestedCollections }"></ng-container>
</ul>
</ng-container>
</ng-container>

View File

@@ -6,6 +6,8 @@ import {
import { CollectionService } from 'jslib/abstractions/collection.service';
import { FolderService } from 'jslib/abstractions/folder.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { UserService } from 'jslib/abstractions/user.service';
import { GroupingsComponent as BaseGroupingsComponent } from 'jslib/angular/components/groupings.component';
@@ -19,8 +21,9 @@ export class GroupingsComponent extends BaseGroupingsComponent {
searchText: string = '';
searchPlaceholder: string = null;
constructor(collectionService: CollectionService, folderService: FolderService) {
super(collectionService, folderService);
constructor(collectionService: CollectionService, folderService: FolderService,
storageService: StorageService, userService: UserService) {
super(collectionService, folderService, storageService, userService);
}
searchTextChanged() {

View File

@@ -42,7 +42,7 @@
<input type="checkbox" [(ngModel)]="c.checked" name="Collection[{{i}}].Checked" appStopProp>
</td>
<td>
<span appStopProp>{{c.name}}</span>
{{c.name}}
</td>
</tr>
</tbody>

View File

@@ -1,94 +1,33 @@
import {
Component,
EventEmitter,
Input,
OnDestroy,
OnInit,
Output,
} from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { CipherService } from 'jslib/abstractions/cipher.service';
import { CollectionService } from 'jslib/abstractions/collection.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { UserService } from 'jslib/abstractions/user.service';
import { Organization } from 'jslib/models/domain/organization';
import { CipherView } from 'jslib/models/view/cipherView';
import { CollectionView } from 'jslib/models/view/collectionView';
import { ShareComponent as BaseShareComponent } from 'jslib/angular/components/share.component';
@Component({
selector: 'app-vault-share',
templateUrl: 'share.component.html',
})
export class ShareComponent implements OnInit, OnDestroy {
@Input() cipherId: string;
@Input() organizationId: string;
@Output() onSharedCipher = new EventEmitter();
formPromise: Promise<any>;
cipher: CipherView;
collections: CollectionView[] = [];
organizations: Organization[] = [];
private writeableCollections: CollectionView[] = [];
constructor(private collectionService: CollectionService, private analytics: Angulartics2,
private toasterService: ToasterService, private i18nService: I18nService,
private userService: UserService, private cipherService: CipherService) { }
async ngOnInit() {
const cipherDomain = await this.cipherService.get(this.cipherId);
this.cipher = await cipherDomain.decrypt();
const allCollections = await this.collectionService.getAllDecrypted();
this.writeableCollections = allCollections.filter((c) => !c.readOnly);
this.organizations = await this.userService.getAllOrganizations();
if (this.organizationId == null && this.organizations.length > 0) {
this.organizationId = this.organizations[0].id;
}
this.filterCollections();
export class ShareComponent extends BaseShareComponent implements OnDestroy {
constructor(collectionService: CollectionService, platformUtilsService: PlatformUtilsService,
i18nService: I18nService, userService: UserService,
cipherService: CipherService) {
super(collectionService, platformUtilsService, i18nService, userService, cipherService);
}
ngOnDestroy() {
this.selectAll(false);
}
filterCollections() {
this.selectAll(false);
if (this.organizationId == null || this.writeableCollections.length === 0) {
this.collections = [];
} else {
this.collections = this.writeableCollections.filter((c) => c.organizationId === this.organizationId);
}
}
async submit() {
const cipherDomain = await this.cipherService.get(this.cipherId);
const cipherView = await cipherDomain.decrypt();
const attachmentPromises: Array<Promise<any>> = [];
if (cipherView.attachments != null) {
for (const attachment of cipherView.attachments) {
const promise = this.cipherService.shareAttachmentWithServer(attachment,
cipherView.id, this.organizationId);
attachmentPromises.push(promise);
}
}
const checkedCollectionIds = this.collections.filter((c) => (c as any).checked).map((c) => c.id);
try {
this.formPromise = Promise.all(attachmentPromises).then(async () => {
await this.cipherService.shareWithServer(cipherView, this.organizationId, checkedCollectionIds);
this.onSharedCipher.emit();
this.analytics.eventTrack.next({ action: 'Shared Cipher' });
this.toasterService.popAsync('success', null, this.i18nService.t('sharedItem'));
});
await this.formPromise;
} catch { }
}
check(c: CollectionView, select?: boolean) {
(c as any).checked = select == null ? !(c as any).checked : select;
}
@@ -97,15 +36,4 @@ export class ShareComponent implements OnInit, OnDestroy {
const collections = select ? this.collections : this.writeableCollections;
collections.forEach((c) => this.check(c, select));
}
get canSave() {
if (this.collections != null) {
for (let i = 0; i < this.collections.length; i++) {
if ((this.collections[i] as any).checked) {
return true;
}
}
}
return false;
}
}

View File

@@ -187,7 +187,7 @@ export class VaultComponent implements OnInit, OnDestroy {
}
async filterCollection(collectionId: string) {
this.ciphersComponent.showAddNew = false;
this.ciphersComponent.showAddNew = true;
this.groupingsComponent.searchPlaceholder = this.i18nService.t('searchCollection');
await this.ciphersComponent.load((c) => c.collectionIds != null && c.collectionIds.indexOf(collectionId) > -1);
this.clearFilters();
@@ -225,6 +225,7 @@ export class VaultComponent implements OnInit, OnDestroy {
let madeAttachmentChanges = false;
childComponent.onUploadedAttachment.subscribe(() => madeAttachmentChanges = true);
childComponent.onDeletedAttachment.subscribe(() => madeAttachmentChanges = true);
childComponent.onReuploadedAttachment.subscribe(() => madeAttachmentChanges = true);
this.modal.onClosed.subscribe(async () => {
this.modal = null;
@@ -327,6 +328,13 @@ export class VaultComponent implements OnInit, OnDestroy {
const component = this.editCipher(null);
component.type = this.type;
component.folderId = this.folderId === 'none' ? null : this.folderId;
if (this.collectionId != null) {
const collection = this.groupingsComponent.collections.filter((c) => c.id === this.collectionId);
if (collection.length > 0) {
component.organizationId = collection[0].organizationId;
component.collectionIds = [this.collectionId];
}
}
}
editCipher(cipher: CipherView) {

View File

@@ -38,7 +38,7 @@
"message": "Heslo"
},
"passphrase": {
"message": "Passphrase"
"message": "Heslová fráze"
},
"notes": {
"message": "Poznámky"
@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Přepnout viditelnost"
},
"toggleCollapse": {
"message": "Přepnout sbalení",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Vygenerovat heslo"
},
@@ -436,10 +440,10 @@
"message": "Položka byla upravena"
},
"sharedItem": {
"message": "Položka byla nasdílena"
"message": "Položka byla sdílena"
},
"sharedItems": {
"message": "Položky byly nasdíleny"
"message": "Položky byly sdíleny"
},
"deleteItem": {
"message": "Smazat položku"
@@ -547,7 +551,7 @@
"message": "Zadejte e-mailovou adresu pro zaslání nápovědy k hlavnímu heslu."
},
"getMasterPasswordHint": {
"message": "Získat nápovědu pro hlavní heslo"
"message": "Zaslat nápovědu k hlavnímu heslu"
},
"emailRequired": {
"message": "E-mailová adresa je povinná."
@@ -643,7 +647,7 @@
"message": "Pamatuj si mě"
},
"sendVerificationCodeEmailAgain": {
"message": "Zaslat znovu ověřovací kód na e-mail"
"message": "Znovu zaslat ověřovací kód na e-mail"
},
"useAnotherTwoStepMethod": {
"message": "Použít jinou metodu dvoufázového přihlášení"
@@ -683,7 +687,7 @@
"message": "YubiKey OTP bezpečnostní klíč"
},
"yubiKeyDesc": {
"message": "Použít YubiKey pro přístup k vašemu trezoru. Podporuje YubiKey 4, 4 Nano, 4C a NEO zařízení."
"message": "Použít YubiKey pro přístup k vašemu trezoru. Podporuje YubiKey 4. série, 5. série a zařízení řady NEO."
},
"duoDesc": {
"message": "Ověřit pomocí Duo Security prostřednictvím aplikace Duo Mobile, SMS, telefonního hovoru nebo U2F bezpečnostního kódu.",
@@ -715,10 +719,10 @@
"message": "Organizace"
},
"shareDesc": {
"message": "Vyberte organizaci se kterou chcete sdílet tuto položku. Sdílením přenese vlastnictví položky na organizaci a již nadále nebudete přímým vlastníkem této položky."
"message": "Vyberte organizaci se kterou chcete tuto položku sdílet. Sdílením přenese vlastnictví položky na organizaci a již nadále nebudete přímým vlastníkem."
},
"shareManyDesc": {
"message": "Vyberte organizaci se kterou chcete sdílet tyto položky. Sdílením přenese vlastnictví položek na organizaci a již nadále nebudete přímým vlastníkem těchto položek."
"message": "Vyberte organizaci se kterou chcete tyto položky sdílet. Sdílením přenese vlastnictví položek na organizaci a již nadále nebudete přímým vlastníkem."
},
"collectionsDesc": {
"message": "Upravit kolekce, ve kterých je tato položka sdílená. Pouze uživatelé organizace, kteří mají přístup k těmto kolekcím, budou moci tuto položku vidět."
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Vybrali jste $COUNT$ položek. $SHAREABLE_COUNT$ položek je možné sdílet a $NONSHAREABLE_COUNT$ položek ne. Položky s přílohami musí být sdíleny jednotlivě.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -799,10 +803,10 @@
"message": "Délka"
},
"numWords": {
"message": "Number of Words"
"message": "Počet slov"
},
"wordSeparator": {
"message": "Word Separator"
"message": "Oddělovač slov"
},
"passwordHistory": {
"message": "Historie hesel"
@@ -916,13 +920,13 @@
"message": "Vymazat celý trezor"
},
"purgedOrganizationVault": {
"message": "Purged organization vault."
"message": "Trezor organizace byl vyprázdněn."
},
"purgeVaultDesc": {
"message": "Pokračujte níže ke smazání všech položek a složek ve vašem trezoru. Položky sdílené s organizací nebudou smazány."
"message": "Chcete-li smazat všechny položky a složky ve vašem trezoru, pokračujte podle následujících pokynů. Položky sdílené s organizací nebudou smazány."
},
"purgeOrgVaultDesc": {
"message": "Proceed below to delete all items in the organization's vault."
"message": "Chcete-li smazat všechny položky v trezoru organizace, pokračujte podle následujících pokynů."
},
"purgeVaultWarning": {
"message": "Vymazání trezoru je trvalé. Tuto akci nelze vrátit zpět."
@@ -1151,7 +1155,7 @@
"message": "Přidání nového YubiKey k vašemu účtu"
},
"twoFactorYubikeyPlugIn": {
"message": "Připojte YubiKey (NEO nebo 4. řada) do USB portu počítače."
"message": "Připojte YubiKey do USB portu počítače."
},
"twoFactorYubikeySelectKey": {
"message": "Vyberte první prázdné pole YubiKey níže."
@@ -1181,7 +1185,7 @@
}
},
"u2fkeyX": {
"message": "U2F Key $INDEX$",
"message": "U2F klíč $INDEX$",
"placeholders": {
"index": {
"content": "$1",
@@ -1232,13 +1236,13 @@
"message": "Přidání bezpečnostního klíče FIDO U2F k vašemu účtu"
},
"removeU2fConfirmation": {
"message": "Are you sure you want to remove this security key?"
"message": "Opravdu chcete odebrat tento bezpečnostní klíč?"
},
"readKey": {
"message": "Read Key"
"message": "Přečíst klíč"
},
"keyCompromised": {
"message": "Key is compromised."
"message": "Klíč je prozrazen."
},
"twoFactorU2fGiveName": {
"message": "Give the security key a friendly name to identify it."
@@ -1250,7 +1254,7 @@
"message": "Pokud má bezpečnostní klíč tlačítko, zmáčkněte jej."
},
"twoFactorU2fSaveForm": {
"message": "Save the form."
"message": "Uložte formulář."
},
"twoFactorU2fWarning": {
"message": "Z důvodu omezení různých platforem, nemůže být FIDO U2F použit ve všech aplikacích Bitwarden. Měli byste povolit jiný způsob dvoufázového přihlášení pro případy, kdy nelze FIDO U2F použít. Podporované platformy:"
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Doplňky"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Další úložiště (GB)"
},
"additionalStorageGbDesc": {
"message": "# dalších GB"
},
"additionalStorageDesc": {
"message": "Vybraný plán obsahuje $SIZE$ šifrovaného uložiště. Můžete si přikoupit další prostor za $PRICE$ za každý další 1 GB ročně.",
"additionalStorageIntervalDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1445,19 +1469,19 @@
"message": "Čeká na zrušení"
},
"subscriptionPendingCanceled": {
"message": "The subscription has been marked for cancellation at the end of the current billing period."
"message": "Předplatné bude zrušeno na konci aktuálního fakturačního období."
},
"reinstateSubscription": {
"message": "Obnovit předplatné"
},
"reinstateConfirmation": {
"message": "Are you sure you want to remove the pending cancellation request and reinstate your subscription?"
"message": "Opravdu chcete zrušit požadavek na ukončení předplatného a obnovit původní předplatné?"
},
"reinstated": {
"message": "Předplatné bylo obnoveno"
},
"cancelConfirmation": {
"message": "Are you sure you want to cancel? You will lose access to all of this subscription's features at the end of this billing cycle."
"message": "Opravdu chcete zrušit předplatné? Na konci fakturačního období přijdete o veškeré výhody plynoucí z vybraného plánu."
},
"canceledSubscription": {
"message": "Předplatné bylo zrušeno"
@@ -1509,7 +1533,7 @@
}
},
"paymentMethod": {
"message": "Způsob Platby"
"message": "Způsob platby"
},
"noPaymentMethod": {
"message": "No payment method on file."
@@ -1528,7 +1552,7 @@
"message": "Žádné platby."
},
"chargesStatement": {
"message": "Any charges will appear on your statement as $STATEMENT_NAME$.",
"message": " Veškeré platby se na výpisu objeví jako $STATEMENT_NAME$.",
"placeholders": {
"statement_name": {
"content": "$1",
@@ -1585,13 +1609,13 @@
"message": "To upgrade your account to a premium membership you need to upload a valid license file."
},
"uploadLicenseFileOrg": {
"message": "To create an on-premise hosted organization you need to upload a valid license file."
"message": "Pro vytvoření organizace hostované na vlastní doméně, musíte nahrát platný licenční soubor."
},
"accountEmailMustBeVerified": {
"message": "E-mailová adresa vašeho účtu musí být ověřena."
},
"newOrganizationDesc": {
"message": "Organizations allow you to share parts of your vault with others as well as manage related users for a specific entity such as a family, small team, or large company."
"message": "Organizace umožňují sdílení položek vašeho trezoru s ostatními uživateli a také správu uživatelů jako členů rodiny, malého týmu nebo velké organizace."
},
"generalInformation": {
"message": "Obecné informace"
@@ -1600,13 +1624,13 @@
"message": "Název organizace"
},
"accountOwnedBusiness": {
"message": "Tento účet je vlastněn společností,"
"message": "Tento účet je vlastněn firmou."
},
"billingEmail": {
"message": "E-mailová adresa pro fakturaci"
},
"businessName": {
"message": "Název společnosti"
"message": "Název firmy"
},
"chooseYourPlan": {
"message": "Vyberte plán"
@@ -1615,10 +1639,10 @@
"message": "Uživatelé"
},
"userSeats": {
"message": "User Seats"
"message": "Počet uživatelů"
},
"additionalUserSeats": {
"message": "Additional User Seats"
"message": "Další uživatelé"
},
"userSeatsDesc": {
"message": "# of user seats"
@@ -1644,7 +1668,7 @@
"description": "Free as in 'free beer'."
},
"planDescFree": {
"message": "For testing or personal users to share with $COUNT$ other user.",
"message": "Pro testování nebo osobní použití a sdílení s $COUNT$ dalším uživatelem.",
"placeholders": {
"count": {
"content": "$1",
@@ -1656,19 +1680,19 @@
"message": "Rodiny"
},
"planDescFamilies": {
"message": "For personal use, to share with family & friends."
"message": "Pro osobní použití a sdílení s rodinou či přáteli."
},
"planNameTeams": {
"message": "Týmy"
},
"planDescTeams": {
"message": "For businesses and other team organizations."
"message": "Pro firmy a různé týmy."
},
"planNameEnterprise": {
"message": "Enterprise"
},
"planDescEnterprise": {
"message": "For businesses and other large organizations."
"message": "Pro firmy a velké organizace."
},
"freeForever": {
"message": "Navždy zdarma"
@@ -1683,7 +1707,7 @@
}
},
"additionalUsers": {
"message": "Additional Users"
"message": "Další uživatelé"
},
"costPerUser": {
"message": "$COST$ za uživatele",
@@ -1695,7 +1719,7 @@
}
},
"limitedUsers": {
"message": "Limited to $COUNT$ users (including you)",
"message": "Omezeno na $COUNT$ uživatele (včetně vás)",
"placeholders": {
"count": {
"content": "$1",
@@ -1704,7 +1728,7 @@
}
},
"limitedCollections": {
"message": "Limited to $COUNT$ collections",
"message": "Omezeno na $COUNT$ kolekce",
"placeholders": {
"count": {
"content": "$1",
@@ -1722,10 +1746,10 @@
}
},
"addShareUnlimitedUsers": {
"message": "Add and share with unlimited users"
"message": "Neomezený počet uživatelů"
},
"createUnlimitedCollections": {
"message": "Create unlimited collections"
"message": "Neomezený počet kolekcí"
},
"gbEncryptedFileStorage": {
"message": "$SIZE$ šifrovaného úložiště",
@@ -1737,7 +1761,7 @@
}
},
"onPremHostingOptional": {
"message": "On-premise hosting (optional)"
"message": "Možnost hostování na vlastní doméně"
},
"usersGetPremium": {
"message": "Users get access to premium membership features"
@@ -1788,16 +1812,16 @@
"message": "Opravdu chcete tuto organizaci opustit?"
},
"leftOrganization": {
"message": "Organizace byla opuštěna"
"message": "Organizace byla opuštěna."
},
"defaultCollection": {
"message": "Výchozí kolekce"
},
"getHelp": {
"message": "Získat nápovědu"
"message": "Nápověda"
},
"getApps": {
"message": "Získat aplikaci"
"message": "Stáhnout aplikaci"
},
"loggedInAs": {
"message": "Přihlášen jako"
@@ -1806,7 +1830,7 @@
"message": "Protokol událostí"
},
"people": {
"message": "Lidé"
"message": "Uživatelé"
},
"groups": {
"message": "Skupiny"
@@ -1833,13 +1857,13 @@
"message": "Externí ID slouží k propojení této skupiny s externím systémem, například s adresářem uživatelů."
},
"accessControl": {
"message": "Správa přístupů"
"message": "Správa přístupu"
},
"groupAccessAllItems": {
"message": "This group can access and modify all items."
"message": "Tato skupina může vidět a upravovat vše."
},
"groupAccessSelectedCollections": {
"message": "This group can access only the selected collections."
"message": "Tato skupina může vidět a upravovat pouze vybrané kolekce."
},
"readOnly": {
"message": "Pouze pro čtení"
@@ -1875,16 +1899,16 @@
}
},
"userAccessAllItems": {
"message": "This user can access and modify all items."
"message": "Tento uživatel může vidět a upravovat vše."
},
"userAccessSelectedCollections": {
"message": "This user can access only the selected collections."
"message": "Tento uživatel může vidět a upravovat pouze vybrané kolekce."
},
"search": {
"message": "Hledat"
},
"invited": {
"message": "Pozván\/a"
"message": "Pozváno"
},
"accepted": {
"message": "Přijato"
@@ -1908,7 +1932,13 @@
"message": "Uživatel"
},
"userDesc": {
"message": "A regular user with access to your organization's collections."
"message": "Běžný uživatel s přístupem k přiřazeným kolekcím vaší organizace."
},
"manager": {
"message": "Správce"
},
"managerDesc": {
"message": "Správci mohou přistupovat a spravovat přiřazené kolekce ve vaší organizaci."
},
"all": {
"message": "Vše"
@@ -2160,7 +2190,7 @@
"message": "Znovu poslat pozvánku"
},
"hasBeenReinvited": {
"message": "$USER$ has been reinvited.",
"message": "Uživatel $USER$ byl znovu pozván.",
"placeholders": {
"user": {
"content": "$1",
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Potvrdit"
},
"confirmUser": {
"message": "Potvrdit uživatele"
},
"hasBeenConfirmed": {
"message": "Uživatel $USER$ byl potvrzen.",
"placeholders": {
@@ -2184,7 +2217,7 @@
"message": "Potvrdit uživatele"
},
"usersNeedConfirmed": {
"message": "You have users that have accepted their invitation, but still need to be confirmed. Users will not have access to the organization until they are confirmed."
"message": "Někteří uživatelé přijali pozvánku, ale nejdříve musí být potvrzeni. Dokud nedojde k potvrzení, nebudou mít tito uživatelé přístup k organizaci."
},
"startDate": {
"message": "Datum začátku"
@@ -2199,7 +2232,7 @@
"message": "Verify your account's email address to unlock access to all features."
},
"verifyEmailFirst": {
"message": "Your account's email address first must be verified."
"message": "E-mailová adresa vašeho účtu musí být ověřena."
},
"checkInboxForVerification": {
"message": "Check your email inbox for a verification link."
@@ -2208,22 +2241,22 @@
"message": "Vaše e-mailová adresa byla ověřena"
},
"emailVerifiedFailed": {
"message": "Unable to verify your email. Try sending a new verification email."
"message": "Váš e-mail se nepodařilo ověřit. Zkuste odeslat nový ověřovací e-mail."
},
"updateBrowser": {
"message": "Update Browser"
"message": "Aktualizace prohlížeče"
},
"updateBrowserDesc": {
"message": "You are using an unsupported web browser. The web vault may not function properly."
"message": "Používáte nepodporovaný webový prohlížeč. Aplikace nemusí pracovat správně."
},
"joinOrganization": {
"message": "Přidat se k organizaci"
},
"joinOrganizationDesc": {
"message": "You've been invited to join the organization listed above. To accept the invitation, you need to log in or create a new Bitwarden account."
"message": "Byly jste pozváni do výše uvedené organizace. Pro přijetí pozvánky se musíte přihlásit nebo si založit nový účet."
},
"inviteAccepted": {
"message": "Pozvánka byla přijata"
"message": "Pozvánka byla přijata."
},
"inviteAcceptedDesc": {
"message": "You can access this organization once an administrator confirms your membership. We'll send you an email when that happens."
@@ -2265,7 +2298,7 @@
"message": "Proceed below to delete this organization and all associated data. Individual user accounts will remain, though they will not be associated to this organization anymore. "
},
"deleteOrganizationWarning": {
"message": "Deleting the organization is permanent. It cannot be undone."
"message": "Smazání organizace je trvalé. Tuto akci nelze vrátit zpět."
},
"organizationDeleted": {
"message": "Organizace byla smazána."
@@ -2274,13 +2307,13 @@
"message": "Organizace a veškerá související data byla smazána."
},
"organizationUpdated": {
"message": "Organizace byla aktualizována"
"message": "Organizace byla aktualizována."
},
"taxInformation": {
"message": "Tax Information"
"message": "Daňové údaje"
},
"taxInformationDesc": {
"message": "Please contact support to provide (or update) tax information for your invoices."
"message": "Pro poskytnutí nebo aktualizaci daňových údajů pro vaše faktury kontaktujte zákaznickou podporu."
},
"billingPlan": {
"message": "Plán",
@@ -2291,14 +2324,14 @@
"description": "A billing plan\/package. For example: families, teams, enterprise, etc."
},
"changeBillingPlanDesc": {
"message": "Contact customer support if you would like to change your plan. Please ensure that you have an active payment method added to the account.",
"message": "Pokud chcete změnit svůj plán, kontaktujte zákaznickou podporu. Ujistěte se prosím, zda máte k účtu přidán způsob platby.",
"description": "A billing plan\/package. For example: families, teams, enterprise, etc."
},
"invoice": {
"message": "Faktura"
},
"verifyBankAccount": {
"message": "Verify Bank Account"
"message": "Ověření bankovního účtu"
},
"verifyBankAccountDesc": {
"message": "We have made two micro-deposits to your bank account (it may take 1-2 business days to show up). Enter these amounts to verify the bank account."
@@ -2310,13 +2343,13 @@
"message": "Failure to verify the bank account will result in a missed payment and your subscription being disabled."
},
"verifiedBankAccount": {
"message": "Bank account has been verified."
"message": "Bankovní účet byl ověřen."
},
"bankAccount": {
"message": "Bankovní účet"
},
"amountX": {
"message": "Amount $COUNT$",
"message": "Částka $COUNT$",
"description": "Used in bank account verification of micro-deposits. Amount, as in a currency amount. Ex. Amount 1 is $2.00, Amount 2 is $1.50",
"placeholders": {
"count": {
@@ -2339,7 +2372,7 @@
"message": "Typ účtu"
},
"bankAccountTypeCompany": {
"message": "Company (Business)"
"message": "Společnost (firma)"
},
"bankAccountTypeIndividual": {
"message": "Individual (Personal)"
@@ -2386,7 +2419,7 @@
}
},
"keyUpdated": {
"message": "Key Updated"
"message": "Klíč byl upraven."
},
"updateKeyTitle": {
"message": "Aktualizovat klíč"
@@ -2419,16 +2452,16 @@
"message": "Tato funkce je nedostupná pro bezplatné organizace. Přejděte na placené členství a odemkněte více funkcí."
},
"createOrganizationStep1": {
"message": "Create Organization: Step 1"
"message": "Vytvoření organizace: Krok 1"
},
"createOrganizationCreatePersonalAccount": {
"message": "Before creating your organization, you first need to create a free personal account."
"message": "Před vytvořením organizace si musíte nejdříve vytvořit bezplatný osobní účet."
},
"refunded": {
"message": "Platba vrácena"
},
"nothingSelected": {
"message": "Nic jste nevybrali."
"message": "Nevybrali jste žádné položky."
},
"submitAgreePolicies": {
"message": "Klepnutím na tlačítko \"Odeslat\" souhlasíte s následující podmínkami:",
@@ -2447,7 +2480,7 @@
"message": "Možnosti zamknutí"
},
"lockOptionsDesc": {
"message": "Vyberte kdy dojde k automatickému uzamčení trezoru. Pro opětovný přístup do uzamčeného trezoru bude potřeba znovu zadat hlavního heslo."
"message": "Vyberte kdy dojde k automatickému uzamčení trezoru. Pro opětovný přístup do trezoru bude potřeba znovu zadat hlavního heslo."
},
"oneMinute": {
"message": "Po 1 minutě"
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Licence vypršela."
},
"updatedUsers": {
"message": "Updated users"
},
"selected": {
"message": "Vybrané"
},
"ownership": {
"message": "Vlastnictví"
},
"whoOwnsThisItem": {
"message": "Kdo vlastní tuto položku?"
},
"strong": {
"message": "Silné",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Dobré",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Slabé",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Slabé hlavní heslo"
},
"weakMasterPasswordDesc": {
"message": "Hlavní heslo, které jste si vybrali, je slabé. Pro správnou ochranu účtu Bitwarden byste měli použít silné hlavní heslo (nebo heslovou frázi). Opravdu chcete toto heslo použít?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Opravit",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Fráze otisku prstu vašeho účtu",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Slå synlighed til\/fra"
},
"toggleCollapse": {
"message": "Fold sammen\/fold ud",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Generér adgangskode"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Du har valgt $COUNT$ element(er). $SHAREABLE_COUNT$ element(er) er delbare, $NONSHAREABLE_COUNT$ er ikke. Elementer med vedhæftninger skal deles individuelt.",
"shareSelectedItemsCountDesc": {
"message": "Du har valgt $COUNT$ element(er). $SHAREABLE_COUNT$ element(er) kan deles, $NONSHAREABLE_COUNT$ kan ikke.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Tilføjelser"
},
"premiumAccess": {
"message": "Premium adgang"
},
"premiumAccessDesc": {
"message": "Du kan tilføje premium adgang til alle medlemmer af din organisation for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Ekstra lagerplads (GB)"
},
"additionalStorageGbDesc": {
"message": "# af ekstra GB"
},
"additionalStorageDesc": {
"message": "Dit abonnement indeholder $SIZE$ krypteret fillagring. Du kan tilføje ekstra lagerplads til $PRICE$ per GB \/ år.",
"additionalStorageIntervalDesc": {
"message": "Dit abonnement indeholder $SIZE$ krypteret fillagring. Du kan tilføje ekstra lagerplads til $PRICE$ per GB \/ $INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1908,7 +1932,13 @@
"message": "Bruger"
},
"userDesc": {
"message": "En almindelig bruger med adgang til organisationens samlinger."
"message": "En almindelig bruger med adgang til tildelte samlinger i din organisation."
},
"manager": {
"message": "Administrator"
},
"managerDesc": {
"message": "Administratorer kan få adgang til og håndtere tildelte samlinger i din organisation."
},
"all": {
"message": "Alle"
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Bekræft"
},
"confirmUser": {
"message": "Bekræft bruger"
},
"hasBeenConfirmed": {
"message": "$USER$ er blevet bekræftet.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Licensen er udløbet."
},
"updatedUsers": {
"message": "Opdaterede brugere"
},
"selected": {
"message": "Valgt"
},
"ownership": {
"message": "Ejerskab"
},
"whoOwnsThisItem": {
"message": "Hvem ejer dette element?"
},
"strong": {
"message": "Stærk",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "God",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Svag",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Svag hovedadgangskode"
},
"weakMasterPasswordDesc": {
"message": "Hovedadgangskoden du har valgt er svag. Du skal bruge en stærk hovedadgangskode (eller en adgangssætning) for at beskytte din Bitwarden-konto korrekt. Er du sikker på, at du vil bruge denne hovedadgangskode?"
},
"rotateAccountEncKey": {
"message": "Rotér også min kontos krypteringsnøgle"
},
"rotateEncKeyTitle": {
"message": "Rotér krypteringsnøgle"
},
"rotateEncKeyConfirmation": {
"message": "Er du sikker på, at du vil rotere din kontos krypteringsnøgle?"
},
"attachmentsNeedFix": {
"message": "Dette element har gamle filvedhæftninger, der skal repareres."
},
"attachmentFixDesc": {
"message": "Dette er en gammel filvedhæftning, der skal repareres. Klik for at lære mere."
},
"fix": {
"message": "Reparér",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "Der er gamle filvedhæftninger i din boks, der skal repareres, før du kan rotere din kontos krypteringsnøgle."
},
"yourAccountsFingerprint": {
"message": "Din kontos fingeraftrykssætning",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "For at sikre integriteten af dine krypteringsnøgler, bedes du bekræfte brugerens fingeraftrykssætning, inden du fortsætter.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Spørg ikke om at bekræfte fingeraftrykssætning igen",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Sichtbarkeit umschalten"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Passwort generieren"
},
@@ -683,7 +687,7 @@
"message": "YubiKey OTP Sicherheitsschlüssel"
},
"yubiKeyDesc": {
"message": "Verwenden Sie einen YubiKey um auf Ihr Konto zuzugreifen. Funtioniert mit YubiKey 4, Nano 4, 4C und NEO Geräten."
"message": "Verwende einen YubiKey um auf dein Konto zuzugreifen. Funtioniert mit YubiKey 4, Nano 4, 4C und NEO Geräten."
},
"duoDesc": {
"message": "Verifizieren Sie mit Duo Security, indem Sie die Duo Mobile App, SMS, Anrufe oder U2F Sicherheitsschlüssel benutzen.",
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Sie haben $COUNT$ Objekt(e) ausgewählt.\n$SHAREABLE_COUNT$ Objekt(e) können geteilt werden, davon $NONSHAREABLE_COUNT$ jedoch nicht. Objekte mit Anhängen müssen individuell geteilt werden.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -799,10 +803,10 @@
"message": "Länge"
},
"numWords": {
"message": "Number of Words"
"message": "Anzahl der Wörter"
},
"wordSeparator": {
"message": "Word Separator"
"message": "Trennzeichen"
},
"passwordHistory": {
"message": "Kennwort-Historie"
@@ -862,7 +866,7 @@
"message": "Neues Master-Passwort bestätigen"
},
"encKeySettings": {
"message": "Einstellungen des Verschlüsselungsschlüssels"
"message": "Verschlüsselungsschlüssel-Einstellungen"
},
"kdfAlgorithm": {
"message": "KDF-Algorithmus"
@@ -880,7 +884,7 @@
}
},
"kdfIterationsWarning": {
"message": "Wenn Sie die Anzahl der KDF-Iterationen zu hoch setzen, kann es sein, dass das Einloggen in (und Entsperren von) Bitwarden auf langsameren Geräten länger dauert. Wir empfehlen, dass Sie den Wert wiederholt um $INCREMENT$ anheben und auf all ihren Geräten testen.",
"message": "Wenn du die Anzahl der KDF-Iterationen zu hoch setzt, kann es sein, dass das Einloggen in Bitwarden (und Entsperren) auf langsameren Geräten länger dauert. Wir empfehlen, dass du den Wert um $INCREMENT$ Schrittweise anhebest und es auf allen Geräten testest.",
"placeholders": {
"increment": {
"content": "$1",
@@ -892,7 +896,7 @@
"message": "KDF ändern"
},
"encKeySettingsChanged": {
"message": "Einstellungen des Verschlüsselungsschlüssels wurden geändert"
"message": "Verschlüsselungsschlüssel-Einstellungen wurden geändert"
},
"dangerZone": {
"message": "Gefahrenzone"
@@ -916,13 +920,13 @@
"message": "Tresor leeren"
},
"purgedOrganizationVault": {
"message": "Purged organization vault."
"message": "Gelöschter Organisations-Tresor."
},
"purgeVaultDesc": {
"message": "Gehen Sie wie folgt vor, um alle Einträge und Ordner in Ihrem Tresor zu löschen. Einträge, die zu einer Organisation gehören, die Sie mit anderen teilen, werden nicht gelöscht."
},
"purgeOrgVaultDesc": {
"message": "Proceed below to delete all items in the organization's vault."
"message": "Bitte bestätige, dass du alle Inhalte dieses Tresores löschen möchtest."
},
"purgeVaultWarning": {
"message": "Die Leerung des Tresor ist permanent. Sie kann nicht rückgängig gemacht werden."
@@ -1091,10 +1095,10 @@
"message": "Für diese Funktion ist eine Premium-Mitgliedschaft notwendig."
},
"youHavePremiumAccess": {
"message": "Sie haben Zugriff auf Premium-Funktionen"
"message": "Du hast Zugriff auf Premium-Funktionen"
},
"alreadyPremiumFromOrg": {
"message": "Wegen einer Organisation, bei der Sie Mitglied sind, haben Sie bereits Zugriff auf Premium-Funktionen."
"message": "Du hast bereits Zugriff auf Premiumfunktionen weil du Mitglied einer Organisation bist."
},
"manage": {
"message": "Verwalten"
@@ -1151,7 +1155,7 @@
"message": "Einen neuen YubiKey zu Ihrem Konto hinzufügen"
},
"twoFactorYubikeyPlugIn": {
"message": "Stecken Sie den YubiKey (NEO oder 4er Serie) in den USB-Anschluss Ihres Computers."
"message": "Stecke den YubiKey in einen USB-Anschluss deines Computers."
},
"twoFactorYubikeySelectKey": {
"message": "Selektieren Sie unten das erste YubiKey-Eingabefeld."
@@ -1181,7 +1185,7 @@
}
},
"u2fkeyX": {
"message": "U2F Key $INDEX$",
"message": "U2F Schlüssel $INDEX$",
"placeholders": {
"index": {
"content": "$1",
@@ -1232,25 +1236,25 @@
"message": "Fügen Sie Ihrem Konto einen FIDO U2F-Sicherheitsschlüssel hinzu"
},
"removeU2fConfirmation": {
"message": "Are you sure you want to remove this security key?"
"message": "Bist du sicher das du diesen Sicherheitsschlüssel entfernen möchtest?"
},
"readKey": {
"message": "Read Key"
"message": "Schlüssel erfassen"
},
"keyCompromised": {
"message": "Key is compromised."
"message": "Dieser Schlüssel ist kompromitiert."
},
"twoFactorU2fGiveName": {
"message": "Give the security key a friendly name to identify it."
"message": "Gib dem Sicherheitsschlüssel einen passenden Namen um ihn zu erkennen."
},
"twoFactorU2fPlugInReadKey": {
"message": "Plug the security key into your computer's USB port and click the \"Read Key\" button."
"message": "Stecke den Sicherheitsschlüssel in deinen Computer und drücke \"Schlüssel erfassen\"."
},
"twoFactorU2fTouchButton": {
"message": "Wenn der Sicherheitsschlüssel eine Taste hat, drücken Sie die."
},
"twoFactorU2fSaveForm": {
"message": "Save the form."
"message": "Formular speichern."
},
"twoFactorU2fWarning": {
"message": "Aufgrund von Plattformbeschränkungen kann FIDO U2F nicht mit allen Bitwarden-Anwendungen verwendet werden. Sie sollten einen anderen Zwei-Faktor-Authentifizierungsanbieter aktivieren, damit Sie auf Ihr Konto zugreifen können, wenn FIDO U2F nicht verwendet werden kann. Unterstützte Plattformen sind:"
@@ -1262,10 +1266,10 @@
"message": "Es wird darauf gewartet, dass Sie die Taste Ihres Sicherheitsschlüssels betätigen"
},
"twoFactorU2fClickSave": {
"message": "Click the \"Save\" button below to enable this security key for two-step login."
"message": "Drücke \"Speichern\" um den Sicherheitsschlüssel für die Zwei-Schritte Anmeldung zu aktivieren."
},
"twoFactorU2fProblemReadingTryAgain": {
"message": "There was a problem reading the security key. Try again."
"message": "Es gab ein Problem beim lesen des Sicherheitsschlüssels, bitte erneut versuchen."
},
"twoFactorRecoveryYourCode": {
"message": "Ihr Wiederherstellungsschlüssel für die Zwei-Faktor-Anmeldung in Bitwarden"
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Erweiterungen"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Zusätzlicher Speicher (GB)"
},
"additionalStorageGbDesc": {
"message": "# zusätzliche GB"
},
"additionalStorageDesc": {
"message": "Ihr Abo beinhaltet einen $SIZE$ großen verschlüsselten Datenspeicher. Sie können zusätzlichen Speicher für $PRICE$ pro GB \/ Jahr dazubuchen.",
"additionalStorageIntervalDesc": {
"message": "Dein Abo beinhaltet $SIZE$ verschlüsselten Datenspeicher. Du kannst zusätzlichen Speicher für $PRICE$ pro GB\/$INTERVAL$ hinzufügen.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1902,13 +1926,19 @@
"message": "Administrator"
},
"adminDesc": {
"message": " Administratoren können auf alle Einträge, Sammlungen und Benutzer in Ihrer Organisation zugreifen und diese verwalten."
"message": "Administratoren können auf alle Elemente, Sammlungen und Benutzer in der Organisation zugreifen und diese verwalten."
},
"user": {
"message": "Benutzer"
},
"userDesc": {
"message": "Ein normaler Benutzer mit Zugriff auf die Sammlungen Ihrer Organisation."
"message": "Ein normaler Benutzer mit Zugriff auf die ihm zugewiesenen Sammlungen der Organisation."
},
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Manager können auf Ihnen zugewiesene Sammlungen in der Organisation zugreifen und diese verwalten."
},
"all": {
"message": "Alle"
@@ -1950,7 +1980,7 @@
"message": "Benutzerpasswort geändert."
},
"enabledUpdated2fa": {
"message": "Enabled\/updated two-step login."
"message": "Zwei-Faktor-Anmeldung aktiviert\/aktualisiert."
},
"disabled2fa": {
"message": "Zwei-Faktor-Anmeldung deaktiviert."
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Bestätigen"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ wurde bestätigt.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Lizenz ist abgelaufen."
},
"updatedUsers": {
"message": "Aktualisierte Benutzer"
},
"selected": {
"message": "Ausgewählt"
},
"ownership": {
"message": "Besitzer"
},
"whoOwnsThisItem": {
"message": "Wem gehört dieser Eintrag?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Toggle Visibility"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand/collapse state."
},
"generatePassword": {
"message": "Generate Password"
},
@@ -744,8 +748,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not. Items with attachments must be shared individually.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1382,14 +1386,30 @@
"addons": {
"message": "Addons"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ /$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Additional Storage (GB)"
},
"additionalStorageGbDesc": {
"message": "# of additional GB"
},
"additionalStorageDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB /year.",
"additionalStorageIntervalDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB /$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1398,6 +1418,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1905,13 +1929,19 @@
"message": "Admin"
},
"adminDesc": {
"message": " Admins can access and manage all items, collections and users in your organization."
"message": "Admins can access and manage all items, collections and users in your organization."
},
"user": {
"message": "User"
},
"userDesc": {
"message": "A regular user with access to your organization's collections."
"message": "A regular user with access to assigned collections in your organization."
},
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Managers can access and manage assigned collections in your organization."
},
"all": {
"message": "All"
@@ -2174,6 +2204,9 @@
"confirm": {
"message": "Confirm"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ has been confirmed.",
"placeholders": {
@@ -2486,5 +2519,69 @@
},
"licenseIsExpired": {
"message": "License is expired."
},
"updatedUsers": {
"message": "Updated users"
},
"selected": {
"message": "Selected"
},
"ownership": {
"message": "Ownership"
},
"whoOwnsThisItem": {
"message": "Who owns this item?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Alternar visibilidad"
},
"toggleCollapse": {
"message": "Colapsar\/Expandir",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Generar contraseña"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Has seleccionado $COUNT$ elementos. $SHAREABLE_COUNT$ son compartibles, $NONSHAREABLE_COUNT$ no lo son. Los elementos que contengan adjuntos deben ser compartidos de forma individual.",
"shareSelectedItemsCountDesc": {
"message": "Ha seleccionado $COUNT$ elemento(s). $SHAREABLE_COUNT$ elementos son compartibles, $NONSHAREABLE_COUNT$ no.",
"placeholders": {
"count": {
"content": "$1",
@@ -916,13 +920,13 @@
"message": "Purgar caja fuerte"
},
"purgedOrganizationVault": {
"message": "Bóveda de organización purgada."
"message": "Caja fuerte de organización purgada."
},
"purgeVaultDesc": {
"message": "Proceder eliminará todos los elementos y carpetas de tu caja fuerte. Los elementos que petenezcan a una organización con la que compartes contenido, no serán eliminados."
},
"purgeOrgVaultDesc": {
"message": "Proceda a continuación para eliminar todos los elementos de la bóveda de la organización."
"message": "Proceda a continuación para eliminar todos los elementos de la caja fuerte de la organización."
},
"purgeVaultWarning": {
"message": "Purgar tu caja fuerte es permanente. No se puede deshacer."
@@ -1091,10 +1095,10 @@
"message": "Se quiere membrasía Premium para poder utilizar esta característica."
},
"youHavePremiumAccess": {
"message": "Usted tiene acceso premium"
"message": "Tienes acceso premium"
},
"alreadyPremiumFromOrg": {
"message": "Ya tiene acceso a las características premium, debido a que es miembro de una organización."
"message": "Ya tienes acceso a las características premium, debido a una organización de la que eres miembro."
},
"manage": {
"message": "Gestionar"
@@ -1154,7 +1158,7 @@
"message": "Conecta la YubiKey (NEO o serie 4) al puerto USB de tu ordenador."
},
"twoFactorYubikeySelectKey": {
"message": "Elija el primer campo de entrada vacío de YubiKey de abajo."
"message": "Elije el primer campo de entrada vacío de YubiKey de abajo."
},
"twoFactorYubikeyTouchButton": {
"message": "Toca el botón del YubiKey."
@@ -1205,7 +1209,7 @@
"message": "Deshabilitar todas las llaves"
},
"twoFactorDuoDesc": {
"message": "Ingrese la información de la aplicación Bitwarden desde su panel de administración Duo."
"message": "Introduce la información de la aplicación Bitwarden de tu panel de administración Duo."
},
"twoFactorDuoIntegrationKey": {
"message": "Clave de integración"
@@ -1220,16 +1224,16 @@
"message": "Sigue estos pasos para configurar la autenticación en dos pasos con una aplicación autenticadora:"
},
"twoFactorEmailEnterEmail": {
"message": "Ingrese el correo electrónico donde desea recibir los códigos de verificación"
"message": "Introduce el correo electrónico donde deseas recibir los códigos de verificación"
},
"twoFactorEmailEnterCode": {
"message": "Ingrese el código de verificación de 6 dígitos enviado a su correo electrónico"
"message": "Introduce el código de verificación de 6 dígitos enviado a tu correo electrónico"
},
"sendEmail": {
"message": "Enviar correo electrónico"
},
"twoFactorU2fAdd": {
"message": "Agregar una clave de seguridad U2F FIDO a su cuenta"
"message": "Agregar una clave de seguridad U2F FIDO a tu cuenta"
},
"removeU2fConfirmation": {
"message": "¿Estás seguro de que quieres eliminar esta clave de seguridad?"
@@ -1241,37 +1245,37 @@
"message": "La clave está comprometida."
},
"twoFactorU2fGiveName": {
"message": "Asigne un nombre descriptivo a la llave de seguridad."
"message": "Asigna un nombre descriptivo a la llave de seguridad."
},
"twoFactorU2fPlugInReadKey": {
"message": "Conecte la llave de seguridad al puerto USB de su ordenador y haga clic en el botón \"Leer llave\"."
"message": "Conecta la llave de seguridad al puerto USB de tu ordenador y haz clic en el botón \"Leer llave\"."
},
"twoFactorU2fTouchButton": {
"message": "Si la clave de seguridad tiene un botón, tócalo."
},
"twoFactorU2fSaveForm": {
"message": "Guarda el formulario."
"message": "Guardar el formulario."
},
"twoFactorU2fWarning": {
"message": "Debido a limitaciones de la plataforma, FIDO U2F no puede ser usado en todas las aplicaciones de Bitwarden. Debería habilitar otro proveedor de inicio de sesión de dos pasos, para que pueda acceder a su cuenta cuando FIDO U2F no pueda ser utilizado. Plataformas soportadas:"
"message": "Debido a limitaciones de la plataforma, FIDO U2F no puede ser usado en todas las aplicaciones de Bitwarden. Deberías habilitar otro proveedor de inicio de sesión de dos pasos, para que puedas acceder a tu cuenta cuando FIDO U2F no pueda ser utilizado. Plataformas soportadas:"
},
"twoFactorU2fSupportWeb": {
"message": "Bóveda web y extensiones de navegador en un escritorio\/portátil con un navegador compatible con U2F (Chrome, Opera, Vivaldi, o Firefox con FIDO U2F activado)."
"message": "Caja fuerte web y extensiones de navegador en un escritorio\/portátil con un navegador compatible con U2F (Chrome, Opera, Vivaldi, o Firefox con FIDO U2F activado)."
},
"twoFactorU2fWaiting": {
"message": "Esperando que toque el botón de su clave de seguridad"
"message": "Esperando a que toques el botón de tu llave de seguridad"
},
"twoFactorU2fClickSave": {
"message": "Haga clic en el botón \"guardar\" para habilitar esta clave de seguridad para el inicio de sesión de dos pasos."
"message": "Haz clic en el botón \"guardar\" para habilitar esta llave de seguridad para el inicio de sesión de dos pasos."
},
"twoFactorU2fProblemReadingTryAgain": {
"message": "Hubo un problema al leer la clave de seguridad. Inténtalo de nuevo."
"message": "Hubo un problema al leer la llave de seguridad. Inténtalo de nuevo."
},
"twoFactorRecoveryYourCode": {
"message": "Su código de recuperación de inicio de sesión de dos pasos Bitwarden"
"message": "Tu código de recuperación de inicio de sesión de dos pasos de Bitwarden"
},
"twoFactorRecoveryNoCode": {
"message": "Aún no ha habilitado ningún proveedor de inicio de sesión de dos pasos. Después de haber habilitado un proveedor de inicio de sesión de dos pasos, puede volver aquí para ver el código de recuperación."
"message": "Aún no has habilitado ningún proveedor de inicio de sesión en dos pasos. Después de haber habilitado un proveedor de inicio de sesión en dos pasos, puedes volver aquí para ver el código de recuperación."
},
"printCode": {
"message": "Imprimir código",
@@ -1284,16 +1288,16 @@
"message": "Informe de violación de datos"
},
"breachDesc": {
"message": "Una \"violación\" es un incidente en el que los delincuentes informáticos han accedido ilegalmente a los datos de un sitio y los han hecho públicos. Revise los tipos de datos que fueron comprometidos (direcciones de correo electrónico, contraseñas, tarjetas de crédito, etc.) y tome las medidas apropiadas, como cambiar las contraseñas."
"message": "Una \"filtración\" es un incidente en el que los delincuentes informáticos han accedido ilegalmente a los datos de un sitio y los han hecho públicos. Revisa los tipos de datos que fueron comprometidos (direcciones de correo electrónico, contraseñas, tarjetas de crédito, etc.) y toma las medidas apropiadas, como cambiar las contraseñas."
},
"breachCheckUsernameEmail": {
"message": "Verifique cualquier nombre de usuario o dirección de correo electrónico que use."
"message": "Verifica cualquier nombre de usuario o dirección de correo electrónico que utilices."
},
"checkBreaches": {
"message": "Comprobar las violaciones"
"message": "Comprobar filtraciones"
},
"breachUsernameNotFound": {
"message": "$USERNAME$ no se encontró en ninguna violación de datos conocida.",
"message": "$USERNAME$ no se encontró en ninguna filtración de datos conocida.",
"placeholders": {
"username": {
"content": "$1",
@@ -1306,7 +1310,7 @@
"description": "ex. Good News, No Breached Accounts Found!"
},
"breachUsernameFound": {
"message": "$USERNAME$ fue encontrado $COUNT$ diferentes violaciones de datos en línea.",
"message": "$USERNAME$ fue encontrado en $COUNT$ filtración\/es de datos en línea.",
"placeholders": {
"username": {
"content": "$1",
@@ -1334,7 +1338,7 @@
"message": "Se ha producido una filtración"
},
"breachReported": {
"message": "Infracción notificada"
"message": "Filtración reportada"
},
"reportError": {
"message": "Se ha producido un error al intentar cargar el informe. Vuelve a intentarlo"
@@ -1343,7 +1347,7 @@
"message": "Facturación y licencias"
},
"goPremium": {
"message": "Hazte premium",
"message": "Hazte Premium",
"description": "Another way of saying \"Get a premium membership\""
},
"premiumUpdated": {
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Complementos"
},
"premiumAccess": {
"message": "Acceso Premium"
},
"premiumAccessDesc": {
"message": "Puede Agregar acceso premium a todos los miembros de su organización por $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Almacenamiento adicional (GB)"
},
"additionalStorageGbDesc": {
"message": "# de GB adicional"
},
"additionalStorageDesc": {
"message": "Su plan viene con $SIZE$ de almacenamiento de archivos cifrados. Puede agregar almacenamiento adicional por $PRICE$ por GB\/año.",
"additionalStorageIntervalDesc": {
"message": "Su plan viene con $SIZE$ de almacenamiento de archivos cifrados. Puede agregar almacenamiento adicional por $PRICE$ por GB\/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1902,7 +1926,7 @@
"message": "Administrador"
},
"adminDesc": {
"message": "Los administradores pueden acceder y gestionar todos los elementos, coleccionefs y usuarios de la organización."
"message": "Los administradores pueden acceder y gestionar todos los elementos, colecciones y usuarios de la organización."
},
"user": {
"message": "Usuario"
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "Un usuario regular con acceso a las colecciones de su organización."
},
"manager": {
"message": "Gestor"
},
"managerDesc": {
"message": "Los gestores pueden acceder y gestionar colecciones asignadas en tu organización."
},
"all": {
"message": "Todo"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Confirmar"
},
"confirmUser": {
"message": "Confirmar usuario"
},
"hasBeenConfirmed": {
"message": "El usuario $USER$ ha sido confirmado.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Licencia expirada."
},
"updatedUsers": {
"message": "Usuarios actualizados"
},
"selected": {
"message": "Seleccionado"
},
"ownership": {
"message": "Propiedad"
},
"whoOwnsThisItem": {
"message": "¿Quién posee este elemento?"
},
"strong": {
"message": "Fuerte",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Bueno",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Débil",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Contraseña maestra débil"
},
"weakMasterPasswordDesc": {
"message": "La contraseña maestra que ha elegido es débil. Debe usar una contraseña maestra fuerte (o una frase de contraseña) para proteger adecuadamente su cuenta de Bitwarden. ¿Está seguro de que desea utilizar esta contraseña maestra?"
},
"rotateAccountEncKey": {
"message": "También rotar la clave de encriptación de mi cuenta"
},
"rotateEncKeyTitle": {
"message": "Rotar clave de encriptación"
},
"rotateEncKeyConfirmation": {
"message": "¿Está seguro de que desea rotar la clave de encriptación de su cuenta?"
},
"attachmentsNeedFix": {
"message": "Este elemento tiene archivos adjuntos antiguos que deben ser corregidos."
},
"attachmentFixDesc": {
"message": "Este es un archivo adjunto antiguo que necesita ser corregido. Haga clic para obtener más información."
},
"fix": {
"message": "Arreglar",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "Hay archivos adjuntos antiguos en la bóveda que necesitan ser corregidos antes de poder rotar la clave de encriptación de su cuenta."
},
"yourAccountsFingerprint": {
"message": "Frase de la huella digital de su cuenta",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "Para asegurar la integridad de sus claves de encriptación, por favor verifique la frase de la huella digital del usuario antes de continuar.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "No pida verificar la frase de la huella dactilar de nuevo",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Näita sisu"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Loo parool"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Oled valinud $COUNT$ objekti. $SHAREABLE_COUNT$ objekti on jagatavad $NONSHAREABLE_COUNT$ aga ei ole. Objekte millel on lisaks ka manused, tuleb jagada käsitsi.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Lisad"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Lisaruum (GB)"
},
"additionalStorageGbDesc": {
"message": "# lisa GB"
},
"additionalStorageDesc": {
"message": "Sul on kasutada $SIZE$ krüpteeritud failiruumi Soovi korral saad osta lisaruumi hinnaga $PRICE$ GB \/aastas.",
"additionalStorageIntervalDesc": {
"message": "Sul on kasutada $SIZE$ krüpteeritud failiruumi Soovi korral saad osta lisaruumi hinnaga $PRICE$ GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "Tavaline kasutaja, kel on ligipääsu organisatsiooni kirjetele."
},
"manager": {
"message": "Administraator"
},
"managerDesc": {
"message": "Administraatorid pääsevad ligi ja saavad hallata organisatsiooni poolt määratud kollektsioone."
},
"all": {
"message": "Kõik"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Kinnita"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "Kasutaja $USER$ on kinnitatud.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Litsents on aegunud."
},
"updatedUsers": {
"message": "Kasutajad on uuendatud"
},
"selected": {
"message": "Valitud"
},
"ownership": {
"message": "Omanik"
},
"whoOwnsThisItem": {
"message": "Kes seda üksust omab?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Näytä\/piilota"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Luo salasana"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not. Items with attachments must be shared individually.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Lisäosat"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Additional Storage (GB)"
},
"additionalStorageGbDesc": {
"message": "# of additional GB"
},
"additionalStorageDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/year.",
"additionalStorageIntervalDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "A regular user with access to your organization's collections."
},
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Managers can access and manage assigned collections in your organization."
},
"all": {
"message": "Kaikki"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Vahvista"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ on vahvistettu.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Lisenssi on vanhentunut."
},
"updatedUsers": {
"message": "Updated users"
},
"selected": {
"message": "Valittu"
},
"ownership": {
"message": "Omistajuus"
},
"whoOwnsThisItem": {
"message": "Kuka omistaa tämän kohteen?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Afficher\/Masquer"
},
"toggleCollapse": {
"message": "Déplier ou replier",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Générer un mot de passe"
},
@@ -683,7 +687,7 @@
"message": "Clé de sécurité YubiKey OTP"
},
"yubiKeyDesc": {
"message": "Utiliser une YubiKey pour accéder à votre compte. Fonctionne avec les appareils YubiKey 4, 4 Nano, 4C et NEO."
"message": "Utiliser une YubiKey pour accéder à votre compte. Fonctionne avec les appareils YubiKey série 4, série 5 et NEO."
},
"duoDesc": {
"message": "Vérifier avec Duo Security via l'application Duo Mobile, un SMS, un appel vocal ou une clé de sécurité U2F.",
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Vous avez sélectionné $COUNT$ élément(s). $SHAREABLE_COUNT$ éléments peuvent être partagés, $NONSHAREABLE_COUNT$ ne le peuvent pas.\nLes éléments avec des pièces jointes doivent être partagés individuellement.",
"shareSelectedItemsCountDesc": {
"message": "Vous avez sélectionné $COUNT$ élément(s). $SHAREABLE_COUNT$ éléments sont partageables, $NONSHAREABLE_COUNT$ ne le sont pas.",
"placeholders": {
"count": {
"content": "$1",
@@ -1151,7 +1155,7 @@
"message": "Ajouter une nouvelle YubiKey à votre compte"
},
"twoFactorYubikeyPlugIn": {
"message": "Branchez la YubiKey (NEO ou série 4) dans un port USB de votre ordinateur."
"message": "Branchez la YubiKey dans un port USB de votre ordinateur."
},
"twoFactorYubikeySelectKey": {
"message": "Sélectionnez le premier champ YubiKey libre ci-dessous."
@@ -1262,7 +1266,7 @@
"message": "Attente de l'appui sur le bouton de votre clé de sécurité"
},
"twoFactorU2fClickSave": {
"message": "Cliquez sur le bouton « Sauvegarder » ci-dessous pour activer cette clé de sécurité pour une connexion en deux étapes."
"message": "Cliquez sur le bouton « Enregistrer » ci-dessous pour activer cette clé de sécurité pour une connexion en deux étapes."
},
"twoFactorU2fProblemReadingTryAgain": {
"message": "Un problème est survenu lors de la lecture de la clé de sécurité. Veuillez réessayer."
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Add-ons"
},
"premiumAccess": {
"message": "Accès premium"
},
"premiumAccessDesc": {
"message": "Vous pouvez ajouter un accès premium à tous les membres de votre organisation pour $PRICE$\/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Stockage additionnel (Go)"
},
"additionalStorageGbDesc": {
"message": "# Go additionnels"
},
"additionalStorageDesc": {
"message": "Votre offre comprend $SIZE$ de stockage de fichiers chiffrés. Vous pouvez ajouter du stockage supplémentaire pour $PRICE$ par Go\/an.",
"additionalStorageIntervalDesc": {
"message": "Votre offre comprend $SIZE$ de stockage de fichiers chiffrés. Vous pouvez ajouter du stockage supplémentaire pour $PRICE$ par Go\/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "Un utilisateur normal avec accès aux collections de votre organisation."
},
"manager": {
"message": "Gestionnaire"
},
"managerDesc": {
"message": "Les gestionnaires peuvent voir et gérer les collections de votre organisation qui leur ont été assignées."
},
"all": {
"message": "Tous"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Confirmer"
},
"confirmUser": {
"message": "Confirmer l'utilisateur"
},
"hasBeenConfirmed": {
"message": "$USER$ a été confirmé.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "La licence a expiré."
},
"updatedUsers": {
"message": "Utilisateurs mis à jour"
},
"selected": {
"message": "Sélectionné(s)"
},
"ownership": {
"message": "Propriété"
},
"whoOwnsThisItem": {
"message": "À qui appartient cet élément?"
},
"strong": {
"message": "Fort",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Suffisant",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Faible",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Mot de passe maître faible"
},
"weakMasterPasswordDesc": {
"message": "Le mot de passe maître que vous avez choisi est faible. Vous devriez utiliser un mot de passe (ou une phrase de passe) fort(e) pour protéger correctement votre compte Bitwarden. Êtes-vous certain de vouloir utiliser ce mot de passe maître ?"
},
"rotateAccountEncKey": {
"message": "Faire également pivoter la clé de chiffrement de mon compte"
},
"rotateEncKeyTitle": {
"message": "Faire pivoter la clé de chiffrement"
},
"rotateEncKeyConfirmation": {
"message": "Êtes-vous sûr de vouloir modifier la clé de chiffrement de votre compte ?"
},
"attachmentsNeedFix": {
"message": "Cet élément a d'anciennes pièces jointes qui doivent être réparées."
},
"attachmentFixDesc": {
"message": "Il s'agit d'une ancienne pièce jointe qui doit être réparée. Cliquez pour en savoir plus."
},
"fix": {
"message": "Réparer",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "Il y a d'anciennes pièces jointes dans votre coffre qui doivent être réparées avant que vous ne puissiez faire pivoter la clé de chiffrement de votre compte."
},
"yourAccountsFingerprint": {
"message": "La phrase d'empreinte de votre compte",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "Pour assurer l'intégrité de vos clés de chiffrement, merci de vérifier la phrase d'empreinte de l'utilisateur avant de continuer.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Ne plus me demander de vérifier de phrase d'empreinte",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Láthatóság váltása"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Jelszó generálása"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not. Items with attachments must be shared individually.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Addons"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Additional Storage (GB)"
},
"additionalStorageGbDesc": {
"message": "# of additional GB"
},
"additionalStorageDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/year.",
"additionalStorageIntervalDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "A regular user with access to your organization's collections."
},
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Managers can access and manage assigned collections in your organization."
},
"all": {
"message": "All"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Confirm"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ has been confirmed.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "License is expired."
},
"updatedUsers": {
"message": "Updated users"
},
"selected": {
"message": "Selected"
},
"ownership": {
"message": "Ownership"
},
"whoOwnsThisItem": {
"message": "Who owns this item?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -38,7 +38,7 @@
"message": "Password"
},
"passphrase": {
"message": "Passphrase"
"message": "Frase segreta"
},
"notes": {
"message": "Note"
@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Mostra\/Nascondi"
},
"toggleCollapse": {
"message": "Attiva\/disattiva Collasso",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Genera Password"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "La selezione comprende $COUNT$ elementi. $SHAREABLE_COUNT$ elementi possono essere condivisi, i restanti $NONSHAREABLE_COUNT$ no. Gli elementi con allegati devono essere condivisi individualmente.",
"shareSelectedItemsCountDesc": {
"message": "Hai selezionato $COUNT$ elemento(i). $SHAREABLE_COUNT$ elementi sono condivisibili, $NONSHAREABLE_COUNT$ non lo sono.",
"placeholders": {
"count": {
"content": "$1",
@@ -799,10 +803,10 @@
"message": "Lunghezza"
},
"numWords": {
"message": "Number of Words"
"message": "Numero di parole"
},
"wordSeparator": {
"message": "Word Separator"
"message": "Separatore parole"
},
"passwordHistory": {
"message": "Cronologia delle password"
@@ -862,16 +866,16 @@
"message": "Conferma Nuova Password Principale"
},
"encKeySettings": {
"message": "Encryption Key Settings"
"message": "Impostazioni chiave di crittografia"
},
"kdfAlgorithm": {
"message": "KDF Algorithm"
"message": "Algoritmo KDF"
},
"kdfIterations": {
"message": "KDF Iterations"
"message": "Iterazioni KDF"
},
"kdfIterationsDesc": {
"message": "Higher KDF iterations can help protect your master password from being brute forced by an attacker. We recommend a value of $VALUE$ or more.",
"message": "Le iterazioni KDF più elevate possono aiutare a proteggere la tua password master dall'essere forzata da un utente malintenzionato. Consigliamo un valore di $VALUE$ o più.",
"placeholders": {
"value": {
"content": "$1",
@@ -880,7 +884,7 @@
}
},
"kdfIterationsWarning": {
"message": "Setting your KDF iterations too high could result in poor performance when logging into (and unlocking) Bitwarden on devices with slower CPUs. We recommend that you increase the value in increments of $INCREMENT$ and then test all of your devices.",
"message": "L'impostazione delle iterazioni KDF troppo elevata potrebbe comportare prestazioni scadenti durante l'accesso (e lo sblocco) di Bitwarden su dispositivi con CPU lente. Ti consigliamo di aumentare il valore in incrementi di $INCREMENT$ e poi testare tutti i tuoi dispositivi.",
"placeholders": {
"increment": {
"content": "$1",
@@ -889,10 +893,10 @@
}
},
"changeKdf": {
"message": "Change KDF"
"message": "Cambia KDF"
},
"encKeySettingsChanged": {
"message": "Encryption Key Settings Changed"
"message": "Impostazioni chiave di crittografia modificate"
},
"dangerZone": {
"message": "Zona Pericolosa"
@@ -916,13 +920,13 @@
"message": "Svuota Cassaforte"
},
"purgedOrganizationVault": {
"message": "Purged organization vault."
"message": "Purifica il caveau dell'organizzazione."
},
"purgeVaultDesc": {
"message": "Procedi in basso per eliminare tutti gli elementi e le cartelle nel Vault. Gli elementi che appartengono a un'organizzazione con cui condividi non verranno eliminati."
},
"purgeOrgVaultDesc": {
"message": "Proceed below to delete all items in the organization's vault."
"message": "Procedi sotto per eliminare tutti gli elementi nel caveau dell'organizzazione."
},
"purgeVaultWarning": {
"message": "Svuotare la tua cassaforte è permanente. Questa azione non è reversibile."
@@ -1091,10 +1095,10 @@
"message": "Un abbonamento premium è richiesto per utilizzare questa funzionalità."
},
"youHavePremiumAccess": {
"message": "You have premium access"
"message": "Hai accesso premium"
},
"alreadyPremiumFromOrg": {
"message": "You already have access to premium features because of an organization you are a member of."
"message": "Hai già accesso alle funzioni premium a causa di un'organizzazione di cui sei membro."
},
"manage": {
"message": "Gestisci"
@@ -1181,7 +1185,7 @@
}
},
"u2fkeyX": {
"message": "U2F Key $INDEX$",
"message": "Chiave U2F $INDEX$",
"placeholders": {
"index": {
"content": "$1",
@@ -1232,25 +1236,25 @@
"message": "Aggiungi una chiave di sicurezza di FIDO U2F al tuo account"
},
"removeU2fConfirmation": {
"message": "Are you sure you want to remove this security key?"
"message": "Sei sicuro di voler rimuovere questa chiave di sicurezza?"
},
"readKey": {
"message": "Read Key"
"message": "Leggi chiave"
},
"keyCompromised": {
"message": "Key is compromised."
"message": "La chiave è compromessa."
},
"twoFactorU2fGiveName": {
"message": "Give the security key a friendly name to identify it."
"message": "Assegna alla chiave di sicurezza un nome descrittivo per identificarla."
},
"twoFactorU2fPlugInReadKey": {
"message": "Plug the security key into your computer's USB port and click the \"Read Key\" button."
"message": "Inserire la chiave di sicurezza nella porta USB del tuo computer e clicca sul pulsante \"Leggi chiave\"."
},
"twoFactorU2fTouchButton": {
"message": "Se la chiave di protezione dispone di un pulsante, premilo."
},
"twoFactorU2fSaveForm": {
"message": "Save the form."
"message": "Salva il modulo."
},
"twoFactorU2fWarning": {
"message": "A causa di limitazioni della piattaforma, FIDO U2F non può essere utilizzato su tutte le applicazioni Bitwarden. Si consiglia di abilitare un altro metodo di verifica in due passaggi in modo da poter accedere al tuo account anche dove FIDO U2F non può essere usato. Piattaforme supportate:"
@@ -1262,10 +1266,10 @@
"message": "In attesa che venga premuto il pulsante della tua chiave di sicurezza"
},
"twoFactorU2fClickSave": {
"message": "Click the \"Save\" button below to enable this security key for two-step login."
"message": "Clicca sul pulsante \"Salva\" qui sotto per abilitare questa chiave di sicurezza per la verifica in due passaggi."
},
"twoFactorU2fProblemReadingTryAgain": {
"message": "There was a problem reading the security key. Try again."
"message": "Si è verificato un problema durante la lettura della chiave di sicurezza. Riprova."
},
"twoFactorRecoveryYourCode": {
"message": "Il tuo codice di recupero Bitwarden per la verifica in due passaggi"
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Estensioni"
},
"premiumAccess": {
"message": "Accesso Premium"
},
"premiumAccessDesc": {
"message": "Puoi aggiungere l'accesso premium a tutti i membri della tua organizzazione per $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Spazio di archiviazione aggiuntivo (GB)"
},
"additionalStorageGbDesc": {
"message": "# di GB aggiuntivi"
},
"additionalStorageDesc": {
"message": "Il piano è dotato di $SIZE$ di archiviazione crittografato. È possibile aggiungere spazio di archiviazione aggiuntivo per $PRICE$ per GB\/anno.",
"additionalStorageIntervalDesc": {
"message": "Il tuo piano viene fornito con $SIZE$ di archiviazione crittografata. Puoi aggiungere ulteriore spazio di archiviazione per $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1740,7 +1764,7 @@
"message": "Self hosting (opzionale)"
},
"usersGetPremium": {
"message": "Users get access to premium membership features"
"message": "Gli utenti ottengono l'accesso alle funzionalità dei membri premium"
},
"controlAccessWithGroups": {
"message": "Controllare l'accesso utente con gruppi"
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "User normale con accesso alle collezioni della tua organizzazione."
},
"manager": {
"message": "Amministratore"
},
"managerDesc": {
"message": "I manager possono accedere e gestire le raccolte assegnate nella propria organizzazione."
},
"all": {
"message": "Tutti"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Conferma"
},
"confirmUser": {
"message": "Conferma utente"
},
"hasBeenConfirmed": {
"message": "$USER$ è stato confermato.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "La licenza è scaduta."
},
"updatedUsers": {
"message": "Utenti aggiornati"
},
"selected": {
"message": "Selezionato"
},
"ownership": {
"message": "Proprietà"
},
"whoOwnsThisItem": {
"message": "A chi appartiene questo elemento?"
},
"strong": {
"message": "Forte",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Buono",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Debole",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Password Principale Debole"
},
"weakMasterPasswordDesc": {
"message": "La password principale che hai scelto è debole. È necessario utilizzare una password principale avanzata (o una Frase segreta) per proteggere adeguatamente il tuo account Bitwarden. Sei sicuro di voler utilizzare questa password principale?"
},
"rotateAccountEncKey": {
"message": "Ruota anche la chiave di crittografia del mio account"
},
"rotateEncKeyTitle": {
"message": "Ruota la chiave di crittografia"
},
"rotateEncKeyConfirmation": {
"message": "Sei sicuro di voler ruotare la chiave di crittografia del tuo account?"
},
"attachmentsNeedFix": {
"message": "Questo elemento ha vecchi file allegati che devono essere corretti."
},
"attachmentFixDesc": {
"message": "Questo è un vecchio file allegato che deve essere corretto. Clicca per saperne di più."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "Ci sono vecchi file allegati nella tua cassaforte che devono essere corretti prima di poter ruotare la chiave di crittografia del tuo account."
},
"yourAccountsFingerprint": {
"message": "Frase dell'impronta digitale del tuo account",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "Per garantire l'integrità delle tue chiavi di crittografia, verifica la frase dell'impronta digitale dell'utente prima di continuare.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Non chiedere di verificare di nuovo la frase dell'impronta digitale",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "표시 전환"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "비밀번호 생성"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not. Items with attachments must be shared individually.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Addons"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Additional Storage (GB)"
},
"additionalStorageGbDesc": {
"message": "# of additional GB"
},
"additionalStorageDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/year.",
"additionalStorageIntervalDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "A regular user with access to your organization's collections."
},
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Managers can access and manage assigned collections in your organization."
},
"all": {
"message": "All"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Confirm"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ has been confirmed.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "라이선스가 만료되었습니다."
},
"updatedUsers": {
"message": "Updated users"
},
"selected": {
"message": "Selected"
},
"ownership": {
"message": "Ownership"
},
"whoOwnsThisItem": {
"message": "Who owns this item?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -38,7 +38,7 @@
"message": "Passord"
},
"passphrase": {
"message": "Passphrase"
"message": "Passfrase"
},
"notes": {
"message": "Notater"
@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Juster synlighet"
},
"toggleCollapse": {
"message": "Bytt mellom skjul\/utvid",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Generer et passord"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Du har valgt $COUNT$ gjenstand(er). $SHAREABLE_COUNT$ gjenstander kan deles, mens $NONSHAREABLE_COUNT$ kan ikke det. Gjenstander med vedlegg må deles individuelt.",
"shareSelectedItemsCountDesc": {
"message": "Du har valgt $COUNT$ gjenstand(er). $SHAREABLE_COUNT$ gjenstander kan deles, $NONSHAREABLE_COUNT$ kan ikke deles.",
"placeholders": {
"count": {
"content": "$1",
@@ -802,7 +806,7 @@
"message": "Antall ord"
},
"wordSeparator": {
"message": "Word Separator"
"message": "Ordadskiller"
},
"passwordHistory": {
"message": "Passordhistorikk"
@@ -865,13 +869,13 @@
"message": "Innstillinger for krypteringsnøkkel"
},
"kdfAlgorithm": {
"message": "KDF Algoritmen"
"message": "KDF-algoritme"
},
"kdfIterations": {
"message": "KDF gjentakelser"
"message": "KDF-gjentakelser"
},
"kdfIterationsDesc": {
"message": "Høyere KDF gjentakelser kan beskytte hovedpassordet fra blir brute tvunget av angriperen. Verdien $VALUE$ eller mer anbefales.",
"message": "Flere KDF-gjentakelser kan hjelpe til med å beskytte superpassordet fra å bli tvunget inn i av en angriper. Vi anbefaler en verdi $VALUE$ eller mer.",
"placeholders": {
"value": {
"content": "$1",
@@ -880,7 +884,7 @@
}
},
"kdfIterationsWarning": {
"message": "Setting your KDF iterations too high could result in poor performance when logging into (and unlocking) Bitwarden on devices with slower CPUs. We recommend that you increase the value in increments of $INCREMENT$ and then test all of your devices.",
"message": "Å velge for mange KDF-gjentakelser kan føre til dårlig ytelse når du logger inn på (og låser opp) Bitwarden på enheter med tregere CPUer. Vi anbefaler at du øker verdien trinnvis, $INCREMENT$ om gangen, og å så teste det på alle dine enheter.",
"placeholders": {
"increment": {
"content": "$1",
@@ -892,7 +896,7 @@
"message": "Endre KDF"
},
"encKeySettingsChanged": {
"message": "Encryption Key Settings Changed"
"message": "Krypteringsnøkkelinnstillingene har blitt endret"
},
"dangerZone": {
"message": "Faresone"
@@ -916,13 +920,13 @@
"message": "Tøm hvelvet"
},
"purgedOrganizationVault": {
"message": "Purged organization vault."
"message": "Tømte organisasjonens hvelv."
},
"purgeVaultDesc": {
"message": "Fortsett nedenfor for å slette alle gjenstander og mapper i ditt hvelv. Gjenstander som tilhører en organisasjon som du deler med, vil ikke bli slettet."
},
"purgeOrgVaultDesc": {
"message": "Proceed below to delete all items in the organization's vault."
"message": "Fortsett nedenfor for å slette alle gjenstandene i organisasjonens hvelv."
},
"purgeVaultWarning": {
"message": "Å tømme hvelvet ditt er permanent. Det kan ikke bli angret på."
@@ -1091,10 +1095,10 @@
"message": "Et Premium-medlemskap er påkrevd for å bruke denne funksjonen."
},
"youHavePremiumAccess": {
"message": "Du har premium tilgang"
"message": "Du har Premium-tilgang"
},
"alreadyPremiumFromOrg": {
"message": "Du har allerede tilgang til premiumfunksjoner på grunn av en organisasjon du er medlem av."
"message": "Du har allerede tilgang til Premium-funksjoner takket være en organisasjon som du er medlem av."
},
"manage": {
"message": "Behandle"
@@ -1181,7 +1185,7 @@
}
},
"u2fkeyX": {
"message": "U2F Key $INDEX$",
"message": "U2F-nøkkel $INDEX$",
"placeholders": {
"index": {
"content": "$1",
@@ -1235,16 +1239,16 @@
"message": "Er du sikker på at du vil fjerne denne sikkerhetsnøkkelen?"
},
"readKey": {
"message": "Read Key"
"message": "Les nøkkel"
},
"keyCompromised": {
"message": "Key is compromised."
"message": "Nøkkelen er kompromittert."
},
"twoFactorU2fGiveName": {
"message": "Give the security key a friendly name to identify it."
"message": "Gi sikkerhetsnøkkelen et vennlig navn for å identifisere den."
},
"twoFactorU2fPlugInReadKey": {
"message": "Plug the security key into your computer's USB port and click the \"Read Key\" button."
"message": "Sett sikkerhetsnøkkelen inn i din datamaskins USB-port, og klikk på «Les nøkkel»-knappen."
},
"twoFactorU2fTouchButton": {
"message": "Dersom sikkerhetsnøkkelen har en knapp, trykk på den."
@@ -1262,10 +1266,10 @@
"message": "Venter på at du skal trykke på knappen på din sikkerhetsnøkkel"
},
"twoFactorU2fClickSave": {
"message": "Click the \"Save\" button below to enable this security key for two-step login."
"message": "Klikk på «Lagre»-knappen nedenfor for å aktivere denne sikkerhetsnøkkelen for 2-trinnsinnlogging."
},
"twoFactorU2fProblemReadingTryAgain": {
"message": "There was a problem reading the security key. Try again."
"message": "Det oppsto et problem med å lese sikkerhetsnøkkelen. Prøv igjen."
},
"twoFactorRecoveryYourCode": {
"message": "Din 2-trinnsinnloggingsgjenopprettingskode for Bitwarden"
@@ -1340,7 +1344,7 @@
"message": "En feil oppstod under forsøk på å laste inn rapporten. Prøv igjen."
},
"billingAndLicensing": {
"message": "Regninger og lisensiering"
"message": "Fakturering og lisensiering"
},
"goPremium": {
"message": "Oppgrader til Premium",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Utvidelser"
},
"premiumAccess": {
"message": "Premium tilgang"
},
"premiumAccessDesc": {
"message": "Du kan gi premium tilgang til alle brukere i din organisasjon for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Ytterligere lagringsplass (GB)"
},
"additionalStorageGbDesc": {
"message": "Antall ekstra GB"
},
"additionalStorageDesc": {
"message": "Din funksjonsplan kommer med $SIZE$ kryptert fillagring. Du kan legge til ytterligere lagring for $PRICE$ per GB per år.",
"additionalStorageIntervalDesc": {
"message": "Din funksjonsplan kommer med $SIZE$ kryptert fillagring. Du kan legge til ytterligere lagring for $PRICE$ per GB per $INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1740,7 +1764,7 @@
"message": "Lokal betjening (valgfritt)"
},
"usersGetPremium": {
"message": "Brukerne får tilgang til premium medlemskap funksjoner"
"message": "Brukerne får tilgang til Premium-medlemskapsfunksjoner"
},
"controlAccessWithGroups": {
"message": "Kontroller brukertilgang med grupper"
@@ -1902,13 +1926,19 @@
"message": "Admin"
},
"adminDesc": {
"message": " Administratorer kan få tilgang til og behandle alle gjenstander, samlinger og brukere i din organisasjon."
"message": "Administratorer kan få tilgang til og behandle alle gjenstander, samlinger og brukere i din organisasjon."
},
"user": {
"message": "Bruker"
},
"userDesc": {
"message": "En vanlig bruker med tilgang til din organisasjons samlinger."
"message": "En vanlig bruker med tilgang til tilegnede samlinger i din organisasjon."
},
"manager": {
"message": "Behandler"
},
"managerDesc": {
"message": "Behandlere har tilgang til og kan behandle tilegnede samlinger i din organisasjon."
},
"all": {
"message": "Alle"
@@ -1950,7 +1980,7 @@
"message": "Endret kontopassordet."
},
"enabledUpdated2fa": {
"message": "Enabled\/updated two-step login."
"message": "Aktiverte\/oppdaterte 2-trinnsinnloggingen."
},
"disabled2fa": {
"message": "Skrudde av 2-trinnsinnlogging."
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Bekreft"
},
"confirmUser": {
"message": "Bekreft bruker"
},
"hasBeenConfirmed": {
"message": "$USER$ har blitt bekreftet.",
"placeholders": {
@@ -2184,7 +2217,7 @@
"message": "Bekreft brukere"
},
"usersNeedConfirmed": {
"message": "Du har brukere som har akseptert sin invitasjon, men må fortsatt bekreftes. Brukere vil ikke ha tilgang til organisasjonen før de er bekreftet."
"message": "Du har brukere som har akseptert sin invitasjon, men som fortsatt bekreftes. Brukere vil ikke ha tilgang til organisasjonen før de er bekreftet."
},
"startDate": {
"message": "Startdato"
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Lisensen har utløpt."
},
"updatedUsers": {
"message": "Oppdaterte brukere"
},
"selected": {
"message": "Valgt"
},
"ownership": {
"message": "Eierskap"
},
"whoOwnsThisItem": {
"message": "Hvem eier dette elementet?"
},
"strong": {
"message": "Sterkt",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Bra",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Svakt",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Svakt Superpassord"
},
"weakMasterPasswordDesc": {
"message": "Superpassordet du har valgt er svakt. Du bør bruke et sterkt superpassord (eller en passordfrase) for å sikre Bitwarden kontoen din på en forsvarlig måte. Er du sikker på at du vil bruke dette superpassordet?"
},
"rotateAccountEncKey": {
"message": "Oppdater også krypteringsnøkkelen til kontoen min"
},
"rotateEncKeyTitle": {
"message": "Oppdater krypteringsnøkkelen"
},
"rotateEncKeyConfirmation": {
"message": "Er du sikker på at du vil oppdatere krypteringsnøkkelen til kontoen din?"
},
"attachmentsNeedFix": {
"message": "Denne oppføringen har gamle fil-vedlegg som må repareres."
},
"attachmentFixDesc": {
"message": "Dette er et gammelt fil-vedlegg som må repareres. Klikk for å se mer."
},
"fix": {
"message": "Reparer",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "Hvelvet ditt har gamle fil-vedlegg som må repareres før du kan oppdatere krypteringsnøkkelen til kontoen din."
},
"yourAccountsFingerprint": {
"message": "Din kontos fingeravtrykksfrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "For å sikre integriteten til krypteringsnøkene dine, vær vennlig å bekrefte brukerens fingeravtrykksfrase før du fortsetter.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Ikke be om bekreftelse av fingeravtrykksfrase flere ganger",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -38,7 +38,7 @@
"message": "Wachtwoord"
},
"passphrase": {
"message": "Passphrase"
"message": "Wachtwoordzin"
},
"notes": {
"message": "Notities"
@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Zichtbaarheid"
},
"toggleCollapse": {
"message": "Inklappen\/uitklappen",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Wachtwoord genereren"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "U heeft $COUNT$ item(s) geselecteerd. Hiervan zijn $SHAREABLE_COUNT$ items deelbaar en $NONSHAREABLE_COUNT$ niet. Items met een bijlage moeten afzonderlijk worden gedeeld.",
"shareSelectedItemsCountDesc": {
"message": "U hebt $COUNT$ item(s) geselecteerd. $SHAREABLE_COUNT$ items kunnen worden gedeeld, $NONSHAREABLE_COUNT$ niet.",
"placeholders": {
"count": {
"content": "$1",
@@ -799,10 +803,10 @@
"message": "Lengte"
},
"numWords": {
"message": "Number of Words"
"message": "Aantal woorden"
},
"wordSeparator": {
"message": "Word Separator"
"message": "Woordscheidingsteken"
},
"passwordHistory": {
"message": "Wachtwoordgeschiedenis"
@@ -916,13 +920,13 @@
"message": "Kluis legen"
},
"purgedOrganizationVault": {
"message": "Purged organization vault."
"message": "Organisatie kluis leeg gemaakt."
},
"purgeVaultDesc": {
"message": "Ga hieronder verder om alle items en mappen in uw kluis te verwijderen. Items die behoren tot een organisatie waarmee u deelt, worden niet verwijderd."
},
"purgeOrgVaultDesc": {
"message": "Proceed below to delete all items in the organization's vault."
"message": "Ga hieronder verder om alle objecten in de organisatie kluis te verwijderen."
},
"purgeVaultWarning": {
"message": "Het leegmaken van uw webkluis is permanent en kan niet ongedaan worden gemaakt."
@@ -1181,7 +1185,7 @@
}
},
"u2fkeyX": {
"message": "U2F Key $INDEX$",
"message": "U2F sleutel $INDEX$",
"placeholders": {
"index": {
"content": "$1",
@@ -1232,25 +1236,25 @@
"message": "Voeg een FIDO U2F beveiligingssleutel toe aan uw account"
},
"removeU2fConfirmation": {
"message": "Are you sure you want to remove this security key?"
"message": "Weet je zeker dat je deze beveiligingssleutel wilt verwijderen?"
},
"readKey": {
"message": "Read Key"
"message": "Lees sleutel"
},
"keyCompromised": {
"message": "Key is compromised."
"message": "Sleutel is gecompromitteerd."
},
"twoFactorU2fGiveName": {
"message": "Give the security key a friendly name to identify it."
"message": "Geef de beveiligingssleutel een beschrijvende naam om deze te identificeren."
},
"twoFactorU2fPlugInReadKey": {
"message": "Plug the security key into your computer's USB port and click the \"Read Key\" button."
"message": "Stop de beveiligingssleutel in een USB-poort van uw computer en klik op de \"Lees sleutel\" knop."
},
"twoFactorU2fTouchButton": {
"message": "Druk op de knop van de beveiligingssleutel wanneer deze aanwezig is."
},
"twoFactorU2fSaveForm": {
"message": "Save the form."
"message": "Sla het formulier op."
},
"twoFactorU2fWarning": {
"message": "Vanwege platformbeperkingen kunnen FIDO U2F niet in alle Bitwarden applicaties gebruikt worden. U zou een andere tweestapsaanmeldingsaanbieder moeten instellen voor wanneer FIDO U2F niet gebruikt kunnen worden. De volgende platformen worden ondersteunt:"
@@ -1262,10 +1266,10 @@
"message": "Wachten tot u op de knop van de beveiligingssleutel hebt gedrukt"
},
"twoFactorU2fClickSave": {
"message": "Click the \"Save\" button below to enable this security key for two-step login."
"message": "Klik op de \"Opslaan\"-knop hier beneden om deze beveiligingssleutel te activeren als tweestapsaanmeldingsmethode."
},
"twoFactorU2fProblemReadingTryAgain": {
"message": "There was a problem reading the security key. Try again."
"message": "Er was een probleem met het lezen van de beveiligingssleutel. Probeer het nogmaals."
},
"twoFactorRecoveryYourCode": {
"message": "Uw Bitwarden tweestapsaanmelding herstelcode"
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Add-ons"
},
"premiumAccess": {
"message": "Premium toegang"
},
"premiumAccessDesc": {
"message": "U kunt premium toegang verlenen aan alle leden van uw organisatie voor $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Extra opslagruimte (GB)"
},
"additionalStorageGbDesc": {
"message": "# extra GB"
},
"additionalStorageDesc": {
"message": "Uw abonnement omvat $SIZE$ gecodeerde bestandsopslag. U kunt extra opslagruimte toevoegen voor $PRICE$ per GB \/ jaar.",
"additionalStorageIntervalDesc": {
"message": "Uw abonnement omvat $SIZE$ gecodeerde bestandsopslag. U kunt extra opslagruimte toevoegen voor $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1839,22 +1863,22 @@
"message": "Deze groep kan alle items inzien en bewerken."
},
"groupAccessSelectedCollections": {
"message": "Deze groep heeft alleen toegang tot de geselecteerde collecties."
"message": "Deze groep heeft alleen toegang tot de geselecteerde verzamelingen."
},
"readOnly": {
"message": "Alleen-lezen"
},
"newCollection": {
"message": "Nieuwe Collectie"
"message": "Nieuwe verzameling"
},
"addCollection": {
"message": "Collectie toevoegen"
"message": "Verzameling toevoegen"
},
"editCollection": {
"message": "Collectie bewerken"
"message": "Verzameling bewerken"
},
"deleteCollectionConfirmation": {
"message": "Weet u zeker dat u deze collectie wilt verwijderen?"
"message": "Weet u zeker dat u deze verzameling wilt verwijderen?"
},
"editUser": {
"message": "Gebruiker bewerken"
@@ -1878,7 +1902,7 @@
"message": "Deze gebruiker kan alle items inzien en bewerken."
},
"userAccessSelectedCollections": {
"message": "Deze gebruiker heeft alleen toegang tot de geselecteerde collecties."
"message": "Deze gebruiker heeft alleen toegang tot de geselecteerde verzamelingen."
},
"search": {
"message": "Zoeken"
@@ -1902,13 +1926,19 @@
"message": "Administrator"
},
"adminDesc": {
"message": "Administrators hebben toegang tot alle items, collecties en gebruikers binnen uw organisatie en kunnen deze ook beheren."
"message": "Administrators hebben toegang tot alle items, verzamelingen en gebruikers binnen uw organisatie en kunnen deze ook beheren."
},
"user": {
"message": "Gebruiker"
},
"userDesc": {
"message": "Een normale gebruiker met toegang tot de collecties van uw organisatie."
"message": "Een normale gebruiker met toegang tot de verzamelingen van uw organisatie."
},
"manager": {
"message": "Beheerder"
},
"managerDesc": {
"message": "Beheerders hebben toegang tot toegewezen collecties binnen uw organisatie en kunnen deze ook beheren."
},
"all": {
"message": "Alles"
@@ -1950,7 +1980,7 @@
"message": "Veranderd account wachtwoord."
},
"enabledUpdated2fa": {
"message": "Enabled\/updated two-step login."
"message": "Tweestapsaanmelden geactiveerd\/bijgewerkt."
},
"disabled2fa": {
"message": "Tweestapsaanmelden uitgeschakeld."
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Bevestig"
},
"confirmUser": {
"message": "Gebruiker bevestigen"
},
"hasBeenConfirmed": {
"message": "$USER$ is bevestigd.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "De licentie is verlopen."
},
"updatedUsers": {
"message": "Bijgewerkte gebruikers"
},
"selected": {
"message": "Geselecteerde"
},
"ownership": {
"message": "Eigendom"
},
"whoOwnsThisItem": {
"message": "Wie is eigenaar van dit object?"
},
"strong": {
"message": "Sterk",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Goed",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Zwak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Zwak hoofdwachtwoord"
},
"weakMasterPasswordDesc": {
"message": "U hebt een zwak hoofdwachtwoord gekozen. Om uw Bitwarden account goed te beschermen zou u een sterk hoofdwachtwoord (of wachtwoordzin) moeten gebruiken. Weet u zeker dat u dit hoofdwachtwoord wilt gebruiken?"
},
"rotateAccountEncKey": {
"message": "De versleuteling van mijn account ook draaien"
},
"rotateEncKeyTitle": {
"message": "Versleuteling roteren"
},
"rotateEncKeyConfirmation": {
"message": "Weet u zeker dat u de versleuteling van uw account wilt roteren?"
},
"attachmentsNeedFix": {
"message": "Dit item heeft oude bestandsbijlagen die aangepast moeten worden."
},
"attachmentFixDesc": {
"message": "Dit is een oude bestandsbijlage die moet worden aangepast. Klik voor meer informatie."
},
"fix": {
"message": "Oplossen",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "Er zijn oude bestandsbijlagen in uw kluis die moeten worden aangepast voordat u de versleuteling van uw account kunt roteren."
},
"yourAccountsFingerprint": {
"message": "Uw account's vingerafdrukfrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "Om de integriteit van uw coderingssleutels te garanderen, controleert u eerst de vingerafdrukfrase van de gebruiker voordat u doorgaat.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Niet meer vragen om de vingerafdrukfrase te controleren",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Pokaż \/ Ukryj"
},
"toggleCollapse": {
"message": "Zwiń\/rozwiń",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Wygeneruj hasło"
},
@@ -683,7 +687,7 @@
"message": "Klucz bezpieczeństwa YubiKey OTP"
},
"yubiKeyDesc": {
"message": "Użyj YubiKey jako metody dostępu do konta. Działa z YubiKey 4, 4 Nano, 4C i urządzeniami NEO."
"message": "Użyj YubiKey jako metody dostępu do konta. Działa z YubiKey serii 4, serii 5 i urządzeniami NEO."
},
"duoDesc": {
"message": "Weryfikacja z użyciem Duo Security poprzez aplikację Duo Mobile, SMS, połączenie telefoniczne lub klucz bezpieczeństwa U2F.",
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Wybrałeś $COUNT$ elementy(ów). $SHAREABLE_COUNT$ elementy(ów) można udostępnić, $NONSHAREABLE_COUNT$ nie. Elementy zawierające załączniki muszą być udostępniane pojedynczo.",
"shareSelectedItemsCountDesc": {
"message": "Zaznaczyłeś $COUNT$ elementy(ów). $SHAREABLE_COUNT$ elementy(ów) możesz udostępnić, $NONSHAREABLE_COUNT$ nie.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Dodatki"
},
"premiumAccess": {
"message": "Dostęp premium"
},
"premiumAccessDesc": {
"message": "Możesz przyznać dostęp premium wszystkim użytkownikom w Twojej organizacji za $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Dodatkowa przestrzeń (GB)"
},
"additionalStorageGbDesc": {
"message": "# dodatkowych GB"
},
"additionalStorageDesc": {
"message": "Twój plan zawiera $SIZE$ szyfrowanej przestrzeni. Możesz zwiększyć rozmiar dostępnej przestrzeni za $PRICE$ za GB\/rok.",
"additionalStorageIntervalDesc": {
"message": "Twój plan zawiera $SIZE$ szyfrowanej przestrzeni. Możesz zwiększyć rozmiar dostępnej przestrzeni za $PRICE$ za GB\/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1902,7 +1926,7 @@
"message": "Administrator"
},
"adminDesc": {
"message": " Administratorzy mają dostęp do wszystkich elementów, kolekcji i użytkowników w Twojej organizacji."
"message": "Administratorzy mają dostęp do wszystkich elementów, kolekcji i użytkowników w Twojej organizacji."
},
"user": {
"message": "Użytkownik"
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "Zwykły użytkownik, posiadający dostęp do kolekcji w Twojej organizacji."
},
"manager": {
"message": "Menedżer"
},
"managerDesc": {
"message": "Menedżerowie mają dostęp i mogą zarządzać kolekcjami przypisanymi do Twojej organizacji."
},
"all": {
"message": "Wszystkie"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Potwierdź"
},
"confirmUser": {
"message": "Zatwierdź użytkownika"
},
"hasBeenConfirmed": {
"message": "Użytkownik $USER$ został potwierdzony.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Licencja wygasła."
},
"updatedUsers": {
"message": "Zaktualizowano użytkowników"
},
"selected": {
"message": "Wybrano"
},
"ownership": {
"message": "Własność"
},
"whoOwnsThisItem": {
"message": "Kto jest właścicielem tego elementu?"
},
"strong": {
"message": "Silne",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Dobre",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Słabe",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Słabe hasło główne"
},
"weakMasterPasswordDesc": {
"message": "Wybrane przez Ciebie hasło główne jest słabe. Powinieneś użyć silniejszego hasła (lub frazy), aby właściwie chronić swoje konto Bitwarden. Czy na pewno chcesz użyć tego hasła głównego?"
},
"rotateAccountEncKey": {
"message": "Zmień także mój klucz szyfrowania"
},
"rotateEncKeyTitle": {
"message": "Zmień klucz szyfrowania"
},
"rotateEncKeyConfirmation": {
"message": "Czy na pewno chcesz zmienić swój klucz szyfrowania?"
},
"attachmentsNeedFix": {
"message": "Ten element posiada stare załączniki, które muszą zostać naprawione."
},
"attachmentFixDesc": {
"message": "To jest stary załącznik, który musi zostać naprawiony. Kliknij, aby dowiedzieć się więcej."
},
"fix": {
"message": "Napraw",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "W Twoim sejfie istnieją stare załączniki, które muszą zostać naprawione, zanim będziesz mógł zmienić klucz szyfrowania Twojego konta."
},
"yourAccountsFingerprint": {
"message": "Hasło szyfrujące dla Twojego konta",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "W celu zapewnienia integralności Twoich kluczy szyfrowania, sprawdź hasło szyfrujące, zanim przejdziesz dalej.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Nie pytaj ponownie o weryfikację hasła szyfrującego",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -10,7 +10,7 @@
}
},
"whatTypeOfItem": {
"message": "Que item é esse?"
"message": "Que tipo de item é este?"
},
"name": {
"message": "Nome"
@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Alternar Visibilidade"
},
"toggleCollapse": {
"message": "Alternar Colapso",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Gerar Senha"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Você selecionou $COUNT$ itens. $SHAREABLE_COUNT$ itens são compartilháveis, $NONSHAREABLE_COUNT$ não são. Itens com anexos devem ser compartilhados individualmente.",
"shareSelectedItemsCountDesc": {
"message": "Você selecionou $COUNT$ item(ns). $SHAREABLE_COUNT$ itens são compartilháveis, $NONSHAREABLE_COUNT$ não são.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Complementos"
},
"premiumAccess": {
"message": "Acesso Premium"
},
"premiumAccessDesc": {
"message": "Você pode adicionar acesso premium a todos os membros da sua organização por $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Armazenamento Adicional (GB)"
},
"additionalStorageGbDesc": {
"message": "# de GB adicional"
},
"additionalStorageDesc": {
"message": "Seu plano vem com $SIZE$ de armazenamento de arquivos criptografados. Você pode adicionar armazenamento adicional por US $PRICE$ por GB \/ano.",
"additionalStorageIntervalDesc": {
"message": "Seu plano tem $SIZE$ de armazenamento criptografado de arquivos. Você pode adicionar armazenamento adicional por $PRICE$ por GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1884,10 +1908,10 @@
"message": "Pesquisar"
},
"invited": {
"message": "Convindado"
"message": "Convidado"
},
"accepted": {
"message": "Aceitado"
"message": "Aceito"
},
"confirmed": {
"message": "Confirmado"
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "Um usuário comum com acesso às coleções da sua organização."
},
"manager": {
"message": "Gerente"
},
"managerDesc": {
"message": "Os gerentes podem acessar e gerenciar coleções atribuídas em sua organização."
},
"all": {
"message": "Todos"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Confirmar"
},
"confirmUser": {
"message": "Confirmar Usuário"
},
"hasBeenConfirmed": {
"message": "$USER$ foi confirmado(a).",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "A licença está expirada."
},
"updatedUsers": {
"message": "Usuários atualizados"
},
"selected": {
"message": "Selecionado"
},
"ownership": {
"message": "Propriedade"
},
"whoOwnsThisItem": {
"message": "Quem possui este item?"
},
"strong": {
"message": "Forte",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Boa",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Fraca",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Senha Mestra Fraca"
},
"weakMasterPasswordDesc": {
"message": "A senha mestra que você selecionou está fraca. Você deve usar uma senha mestra forte (ou uma frase-passe) para proteger a sua conta Bitwarden adequadamente. Tem certeza que deseja usar esta senha mestra?"
},
"rotateAccountEncKey": {
"message": "Também rodar a chave de encriptação da minha conta"
},
"rotateEncKeyTitle": {
"message": "Rodar Chave de Encriptação"
},
"rotateEncKeyConfirmation": {
"message": "Você tem certeza que quer rodar a chave de encriptação da sua conta?"
},
"attachmentsNeedFix": {
"message": "Este item tem anexos de arquivos antigos que precisam ser corrigidos."
},
"attachmentFixDesc": {
"message": "Este é um anexo de arquivo antigo que precisa ser corrigido. Clique para saber mais."
},
"fix": {
"message": "Corrigir",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "Há anexos de arquivos antigos no seu cofre que precisam ser corrigidos antes que você possa girar a chave de criptografia da sua conta."
},
"yourAccountsFingerprint": {
"message": "A sua frase biométrica",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "Para garantir a integridade de suas chaves de criptografia, verifique a frase biométrica do usuário antes de continuar.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Não peça para verificar a frase biométrica novamente",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Изменить видимость"
},
"toggleCollapse": {
"message": "Свернуть\/Развернуть",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Сгенерировать пароль"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Вы выбрали $COUNT$ элемента(-ов). $SHAREABLE_COUNT$ элемента(-ов) являются общими, $NONSHAREABLE_COUNT$ не являются. Делиться элементами с вложениями необходимо по отдельности.",
"shareSelectedItemsCountDesc": {
"message": "Вы выбрали $COUNT$ элемента(ов). $SHAREABLE_COUNT$ являются общими, $NONSHAREABLE_COUNT$ - нет.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Дополнения"
},
"premiumAccess": {
"message": "Премиум-доступ"
},
"premiumAccessDesc": {
"message": "Вы можете добавить премиум-доступ всем членам вашей организации за $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Дополнительное хранилище (ГБ)"
},
"additionalStorageGbDesc": {
"message": "# дополнительных ГБ"
},
"additionalStorageDesc": {
"message": "В ваш план включено $SIZE$ зашифрованного файлового хранилища. Вы можете добавить дополнительное место по $PRICE$ за ГБ \/год.",
"additionalStorageIntervalDesc": {
"message": "В ваш план включено $SIZE$ зашифрованного файлового хранилища. Вы можете добавить дополнительное место по $PRICE$ за ГБ \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1902,13 +1926,19 @@
"message": "Администратор"
},
"adminDesc": {
"message": " Администраторы могут получать доступ и управлять всеми элементами, коллекциями и пользователями в вашей организации."
"message": "Администраторы могут получать доступ и управлять всеми элементами, коллекциями и пользователями вашей организации."
},
"user": {
"message": "Пользователь"
},
"userDesc": {
"message": "Обычный пользователь с доступом к коллекциям вашей организации."
"message": "Обычный пользователь с доступом к назначенным коллекциям вашей организации."
},
"manager": {
"message": "Менеджер"
},
"managerDesc": {
"message": "Менеджеры могут получать доступ и управлять назначенными коллекциями вашей организации."
},
"all": {
"message": "Все"
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Подтвердить"
},
"confirmUser": {
"message": "Подтвердить пользователя"
},
"hasBeenConfirmed": {
"message": "$USER$ был подтвержден.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Срок действия лицензии истек."
},
"updatedUsers": {
"message": "Пользователи обновлены"
},
"selected": {
"message": "Выбрано"
},
"ownership": {
"message": "Владелец"
},
"whoOwnsThisItem": {
"message": "Кому принадлежит этот элемент?"
},
"strong": {
"message": "Сильный",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Хороший",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Слабый",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Слабый мастер-пароль"
},
"weakMasterPasswordDesc": {
"message": "Мастер-пароль, выбранный вами, является слабым. Для надлежащей защиты аккаунта Bitwarden следует использовать сильный мастер-пароль (или парольную фразу). Вы действительно хотите использовать этот мастер-пароль?"
},
"rotateAccountEncKey": {
"message": "Также повернуть ключ шифрования моего аккаунта"
},
"rotateEncKeyTitle": {
"message": "Повернуть ключ шифрования"
},
"rotateEncKeyConfirmation": {
"message": "Вы действительно хотите повернуть ключ шифрования своего аккаунта?"
},
"attachmentsNeedFix": {
"message": "К этому элементу прикреплены старые вложения, которые необходимо исправить."
},
"attachmentFixDesc": {
"message": "Это старое вложение необходимо исправить. Нажмите, чтобы узнать больше."
},
"fix": {
"message": "Исправить",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "В вашем хранилище есть старые вложения, которые необходимо исправить, прежде чем вы сможете повернуть ключ шифрования вашего аккаунта."
},
"yourAccountsFingerprint": {
"message": "Фраза отпечатка вашего аккаунта",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "Чтобы обеспечить целостность ваших ключей шифрования, перед продолжением верифицируйте фразу отпечатка пользователя.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Больше не запрашивать верификацию фразы отпечатка",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Prepnúť viditeľnosť"
},
"toggleCollapse": {
"message": "Prepnúť zloženie",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Generovať heslo"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Vybrali ste $COUNT$ položiek. $SHAREABLE_COUNT$ položiek je zdieľateľných, $NONSHAREABLE_COUNT$ sa nedá zdieľať. Položky s prílohami musia byť zdieľané individuálne.",
"shareSelectedItemsCountDesc": {
"message": "Vybrali ste $COUNT$ položiek. $SHAREABLE_COUNT$ sa dá zdieľať, $NONSHAREABLE_COUNT$ sa nedá zdieľať.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Doplnky"
},
"premiumAccess": {
"message": "Prémium prístup"
},
"premiumAccessDesc": {
"message": "Môžete pridať prémium prístup všetkým členom organizácie za $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Dodatočné úložisko (GB)"
},
"additionalStorageGbDesc": {
"message": "množstvo dodatočných GB"
},
"additionalStorageDesc": {
"message": "Váš plán zahŕňa $SIZE$ šifrovaného úložiska. Môžete si dokúpiť dodatočné miesto za $PRICE$\/GB ročne.",
"additionalStorageIntervalDesc": {
"message": "Váš plán zahŕňa $SIZE$ šifrovaného úložiska. Môžete si dokúpiť dodatočné miesto za $PRICE$\/GB \/ $INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1902,7 +1926,7 @@
"message": "Administrátor"
},
"adminDesc": {
"message": " Administrátori môžu pristupovať k a spravovať všetky položky a používateľov organizácie."
"message": "Administrátori môžu pristupovať k a spravovať všetky položky a používateľov organizácie."
},
"user": {
"message": "Používateľ"
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "Obyčajný používateľ s prístupom k zbierkam organizácie."
},
"manager": {
"message": "Manažér"
},
"managerDesc": {
"message": "Manažéri môžu pristupovať k a spravovať pridelené zbierky v organizácii."
},
"all": {
"message": "Všetky"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Potvrdiť"
},
"confirmUser": {
"message": "Potvrdiť používateľa"
},
"hasBeenConfirmed": {
"message": "$USER$ bol potvrdený.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Licencia vypršala."
},
"updatedUsers": {
"message": "Používatelia aktualizovaní"
},
"selected": {
"message": "Vybraté"
},
"ownership": {
"message": "Vlastníctvo"
},
"whoOwnsThisItem": {
"message": "Kto vlastní túto položku?"
},
"strong": {
"message": "Silné",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Dobré",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Slabé",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Slabé hlavné heslo"
},
"weakMasterPasswordDesc": {
"message": "Hlavné heslo ktoré ste zadali je slabé. Mali by ste použiť silné heslo (alebo frázu) aby ste spoľahlivo ochránili váš Bitwarden účet. Naozaj chcete použiť toto heslo?"
},
"rotateAccountEncKey": {
"message": "Obnoviť aj môj šifrovací kľúč k účtu"
},
"rotateEncKeyTitle": {
"message": "Obnoviť šifrovací kľúč"
},
"rotateEncKeyConfirmation": {
"message": "Naozaj chcete obnoviť váš šifrovací kľúč k účtu?"
},
"attachmentsNeedFix": {
"message": "Táto položka má staré prílohy, ktoré je potrebné opraviť."
},
"attachmentFixDesc": {
"message": "Táto stará príloha musí byť opravená. Kliknite ak sa chcete dozvedieť viac."
},
"fix": {
"message": "Opraviť",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "V trezore máte staré prílohy ktoré musia byť opravené pred tým, než budete môcť obnoviť šifrovací kľúč k účtu."
},
"yourAccountsFingerprint": {
"message": "Fráza odtlačku vašeho účtu",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "Na zabezpečenie integrity šifrovacích kľúčov, skontrolujte frázu odtlačku používateľa pred tým než budete pokračovať.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Nepýtať sa znovu na overenie frázy odtlačku",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Växla synlighet"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Skapa lösenord"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Du har valt $COUNT$ objekt. $SHAREABLE_COUNT$ objekt är delbara, $NONSHAREABLE_COUNT$ är inte det. Objekt med bifogningar måste delas individuellt.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Tillägg"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Ytterligare lagring (GB)"
},
"additionalStorageGbDesc": {
"message": "# ytterligare GB"
},
"additionalStorageDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/year.",
"additionalStorageIntervalDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "En vanlig användare med tillgång till organisationens samlingar."
},
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Managers can access and manage assigned collections in your organization."
},
"all": {
"message": "Alla"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Bekräfta"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ har blivit bekräftad.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Licensen har upphört att gälla."
},
"updatedUsers": {
"message": "Updated users"
},
"selected": {
"message": "Selected"
},
"ownership": {
"message": "Ownership"
},
"whoOwnsThisItem": {
"message": "Who owns this item?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Toggle Visibility"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Generate Password"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not. Items with attachments must be shared individually.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Addons"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Additional Storage (GB)"
},
"additionalStorageGbDesc": {
"message": "# of additional GB"
},
"additionalStorageDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/year.",
"additionalStorageIntervalDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "A regular user with access to your organization's collections."
},
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Managers can access and manage assigned collections in your organization."
},
"all": {
"message": "All"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Confirm"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ has been confirmed.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "License is expired."
},
"updatedUsers": {
"message": "Updated users"
},
"selected": {
"message": "Selected"
},
"ownership": {
"message": "Ownership"
},
"whoOwnsThisItem": {
"message": "Who owns this item?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "Перемкнути видимість"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "Генерувати пароль"
},
@@ -683,7 +687,7 @@
"message": "Ключ безпеки YubiKey OTP"
},
"yubiKeyDesc": {
"message": "Використовуйте YubiKey для доступу до сховища. Працює з YubiKey 4, 4 Nano, 4C та пристроями NEO."
"message": "Використовуйте YubiKey для доступу до облікового запису. Працює з YubiKey серії 4, 5, а також пристроями NEO."
},
"duoDesc": {
"message": "Авторизуйтесь за допомогою Duo Security з використанням мобільного додатку Duo Mobile, SMS, телефонного виклику, або ключа безпеки U2F.",
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "Ви обрали $COUNT$ запис(ів). $SHAREABLE_COUNT$ з них мають спільний доступ, $NONSHAREABLE_COUNT$ — приватні. Записи з вкладеннями повинні оприлюднюватись окремо.",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Додатки"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "Додаткове сховище (ГБ)"
},
"additionalStorageGbDesc": {
"message": "# додаткових ГБ"
},
"additionalStorageDesc": {
"message": "Ваш тарифний план має зашифроване сховище файлів, розміром $SIZE$. Ви можете збільшити обсяг сховища по ціні $PRICE$ за ГБ \/рік.",
"additionalStorageIntervalDesc": {
"message": "У ваш тарифний план включено зашифроване сховище файлів, розміром $SIZE$. Ви можете збільшити обсяг сховища по ціні $PRICE$ за ГБ \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1902,13 +1926,19 @@
"message": "Адміністратор"
},
"adminDesc": {
"message": " Адміністратори мають доступ і можливість керування всіма записами, збірками та користувачами організації."
"message": "Адміністратори мають доступ і можливість керування всіма записами, збірками та користувачами вашої організації."
},
"user": {
"message": "Користувач"
},
"userDesc": {
"message": "Звичайний користувач з доступом до збірок вашої організації."
"message": "Звичайний користувач з доступом до пов'язаних збірок вашої організації."
},
"manager": {
"message": "Менеджер"
},
"managerDesc": {
"message": "Менеджери мають доступ і можуть керувати пов'язаними збірками вашої організації."
},
"all": {
"message": "Усі"
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "Підтвердити"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ було підтверджено.",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "Термін дії ліцензії завершився."
},
"updatedUsers": {
"message": "Оновлені користувачі"
},
"selected": {
"message": "Вибрано"
},
"ownership": {
"message": "Власник"
},
"whoOwnsThisItem": {
"message": "Хто є власником цього елемента?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "切换可见性"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "生成密码"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "您选择了 $COUNT$ 个项目。其中有 $SHAREABLE_COUNT$ 个项目是可以共享的,$NONSHAREABLE_COUNT$ 个项目不能。带附件的项目必须单独共享。",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Addons"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "附加存储 (GB)"
},
"additionalStorageGbDesc": {
"message": "# GB 附加存储"
},
"additionalStorageDesc": {
"message": "您的计划附带 $SIZE$ 的加密存储空间。您也可以用 $PRICE$ 每 GB 每购买附加存储。",
"additionalStorageIntervalDesc": {
"message": "您的计划附带 $SIZE$ 的加密存储空间。您也可以用 $PRICE$ 每 GB 每 $INTERVAL$ 购买附加存储。",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "具有对组织集合的访问权限的普通用户。"
},
"manager": {
"message": "管理员"
},
"managerDesc": {
"message": "经理可以访问和管理组织中分配的集合。"
},
"all": {
"message": "全部"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "确认"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "已确认 $USER$。",
"placeholders": {
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "授权已过期"
},
"updatedUsers": {
"message": "更新用户"
},
"selected": {
"message": "已选择"
},
"ownership": {
"message": "所有权"
},
"whoOwnsThisItem": {
"message": "谁拥有这个项目?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -38,7 +38,7 @@
"message": "密碼"
},
"passphrase": {
"message": "Passphrase"
"message": "密碼"
},
"notes": {
"message": "筆記"
@@ -207,6 +207,10 @@
"toggleVisibility": {
"message": "切換可見度"
},
"toggleCollapse": {
"message": "Toggle Collapse",
"description": "Toggling an expand\/collapse state."
},
"generatePassword": {
"message": "產生密碼"
},
@@ -741,8 +745,8 @@
}
}
},
"shareSelectedItemsDesc": {
"message": "您已經選取了 $COUNT$ 個項目。 $SHAREABLE_COUNT$ 個項目是可以分享的,$NONSHAREABLE_COUNT$ 則否。有附件的的項目必須單獨分享。",
"shareSelectedItemsCountDesc": {
"message": "You have selected $COUNT$ item(s). $SHAREABLE_COUNT$ items are sharable, $NONSHAREABLE_COUNT$ are not.",
"placeholders": {
"count": {
"content": "$1",
@@ -799,10 +803,10 @@
"message": "長度"
},
"numWords": {
"message": "Number of Words"
"message": "字數"
},
"wordSeparator": {
"message": "Word Separator"
"message": "文字分隔字元"
},
"passwordHistory": {
"message": "密碼歷史記錄"
@@ -943,7 +947,7 @@
"message": "帳戶已刪除"
},
"accountDeletedDesc": {
"message": "Your account has been closed and all associated data has been deleted."
"message": "您的帳戶已經關閉, 所有關聯資料已經被刪除。"
},
"myAccount": {
"message": "我的帳戶"
@@ -955,10 +959,10 @@
"message": "匯入資料"
},
"importSuccess": {
"message": "Data has been successfully imported into your vault."
"message": "資料已經成功匯入到您的密碼庫中。"
},
"importFormatError": {
"message": "Data is not formatted correctly. Please check your import file and try again."
"message": "資料格式不正確。請檢查您匯入檔, 再重新匯入。"
},
"importNothingError": {
"message": "沒有匯入任何內容。"
@@ -1038,7 +1042,7 @@
"message": "新增自訂網域"
},
"newCustomDomainDesc": {
"message": "Enter a list of domains separated by commas. Only \"base\" domains are allowed. Do not enter subdomains. For example, enter \"google.com\" instead of \"www.google.com\". You can also enter \"androidapp:\/\/package.name\" to associate an android app with other website domains."
"message": "輸入不同域名時以逗號分隔.只允許輸入域名。不能輸入子網域名稱。例如, 輸入 \"google. com\" 而不是 \"www.google.com\"。您還可以輸入 \"androidapp:\/\/package.name\" 將 android 應用程式 與其他網站域相關聯。"
},
"customDomainX": {
"message": "自訂網域 $INDEX$",
@@ -1091,7 +1095,7 @@
"message": "進階會員才可使用此功能。"
},
"youHavePremiumAccess": {
"message": "You have premium access"
"message": "您有進階版存取權限"
},
"alreadyPremiumFromOrg": {
"message": "You already have access to premium features because of an organization you are a member of."
@@ -1103,19 +1107,19 @@
"message": "停用"
},
"twoStepLoginProviderEnabled": {
"message": "This two-step login provider is enabled on your account."
"message": "您的帳戶已經啟用兩步驗證"
},
"twoStepLoginAuthDesc": {
"message": "Enter your master password to modify two-step login settings."
"message": "輸入您的主密碼以改兩步驗證設定"
},
"twoStepAuthenticatorDesc": {
"message": "Follow these steps to set up two-step login with an authenticator app:"
},
"twoStepAuthenticatorDownloadApp": {
"message": "Download a two-step authenticator app"
"message": "下載兩步驗證APP"
},
"twoStepAuthenticatorNeedApp": {
"message": "Need a two-step authenticator app? Download one of the following"
"message": "需要兩步驗證器APP下載以下應用之一"
},
"iosDevices": {
"message": "iOS 裝置"
@@ -1130,7 +1134,7 @@
"message": "These apps are recommended, however, other authenticator apps will also work."
},
"twoStepAuthenticatorScanCode": {
"message": "Scan this QR code with your authenticator app"
"message": "使用您的兩步驟APP驗證掃描此QR-Code"
},
"key": {
"message": "金鑰"
@@ -1235,7 +1239,7 @@
"message": "Are you sure you want to remove this security key?"
},
"readKey": {
"message": "Read Key"
"message": "讀取金鑰"
},
"keyCompromised": {
"message": "Key is compromised."
@@ -1250,7 +1254,7 @@
"message": "If the security key has a button, touch it."
},
"twoFactorU2fSaveForm": {
"message": "Save the form."
"message": "儲存表單"
},
"twoFactorU2fWarning": {
"message": "Due to platform limitations, FIDO U2F cannot be used on all Bitwarden applications. You should enable another two-step login provider so that you can access your account when FIDO U2F cannot be used. Supported platforms:"
@@ -1379,14 +1383,30 @@
"addons": {
"message": "Addons"
},
"premiumAccess": {
"message": "Premium Access"
},
"premiumAccessDesc": {
"message": "You can add premium access to all members of your organization for $PRICE$ \/$INTERVAL$.",
"placeholders": {
"price": {
"content": "$1",
"example": "$3.33"
},
"interval": {
"content": "$2",
"example": "'month' or 'year'"
}
}
},
"additionalStorageGb": {
"message": "額外的儲存空間 (GB)"
},
"additionalStorageGbDesc": {
"message": "# of additional GB"
},
"additionalStorageDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/year.",
"additionalStorageIntervalDesc": {
"message": "Your plan comes with $SIZE$ of encrypted file storage. You can add additional storage for $PRICE$ per GB \/$INTERVAL$.",
"placeholders": {
"size": {
"content": "$1",
@@ -1395,6 +1415,10 @@
"price": {
"content": "$2",
"example": "$4.00"
},
"interval": {
"content": "$3",
"example": "'month' or 'year'"
}
}
},
@@ -1469,7 +1493,7 @@
"message": "狀態"
},
"nextCharge": {
"message": "Next Charge"
"message": "下一次收費"
},
"details": {
"message": "詳細資料"
@@ -1615,7 +1639,7 @@
"message": "使用者"
},
"userSeats": {
"message": "User Seats"
"message": "使用者數量"
},
"additionalUserSeats": {
"message": "Additional User Seats"
@@ -1910,6 +1934,12 @@
"userDesc": {
"message": "A regular user with access to your organization's collections."
},
"manager": {
"message": "Manager"
},
"managerDesc": {
"message": "Managers can access and manage assigned collections in your organization."
},
"all": {
"message": "全部"
},
@@ -2171,6 +2201,9 @@
"confirm": {
"message": "確認"
},
"confirmUser": {
"message": "Confirm User"
},
"hasBeenConfirmed": {
"message": "$USER$ has been confirmed.",
"placeholders": {
@@ -2268,7 +2301,7 @@
"message": "Deleting the organization is permanent. It cannot be undone."
},
"organizationDeleted": {
"message": "Organization Deleted"
"message": "已刪除組織"
},
"organizationDeletedDesc": {
"message": "The organization and all associated data has been deleted."
@@ -2483,5 +2516,69 @@
},
"licenseIsExpired": {
"message": "授權已過期。"
},
"updatedUsers": {
"message": "更新使用者"
},
"selected": {
"message": "已選擇"
},
"ownership": {
"message": "所有權"
},
"whoOwnsThisItem": {
"message": "誰擁有這個項目?"
},
"strong": {
"message": "Strong",
"description": "ex. A strong password. Scale: Weak -> Good -> Strong"
},
"good": {
"message": "Good",
"description": "ex. A good password. Scale: Weak -> Good -> Strong"
},
"weak": {
"message": "Weak",
"description": "ex. A weak password. Scale: Weak -> Good -> Strong"
},
"weakMasterPassword": {
"message": "Weak Master Password"
},
"weakMasterPasswordDesc": {
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
},
"rotateAccountEncKey": {
"message": "Also rotate my account's encryption key"
},
"rotateEncKeyTitle": {
"message": "Rotate Encryption Key"
},
"rotateEncKeyConfirmation": {
"message": "Are you sure you want to rotate your account's encryption key?"
},
"attachmentsNeedFix": {
"message": "This item has old file attachments that need to be fixed."
},
"attachmentFixDesc": {
"message": "This is an old file attachment the needs to be fixed. Click to learn more."
},
"fix": {
"message": "Fix",
"description": "This is a verb. ex. 'Fix The Car'"
},
"oldAttachmentsNeedFixDesc": {
"message": "There are old file attachments in your vault that need to be fixed before you can rotate your account's encryption key."
},
"yourAccountsFingerprint": {
"message": "Your account's fingerprint phrase",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"fingerprintEnsureIntegrityVerify": {
"message": "To ensure the integrity of your encryption keys, please verify the user's fingerprint phrase before continuing.",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
},
"dontAskFingerprintAgain": {
"message": "Don't ask to verify fingerprint phrase again",
"description": "A 'fingerprint phrase' is a unique word phrase (similar to a passphrase) that a user can use to authenticate their public key with another user, for the purposes of sharing."
}
}

View File

@@ -204,7 +204,14 @@ input, select, textarea {
margin-left: 1.1em;
.fa-li {
left: -24px;
left: -17px;
width: 1.1em;
}
}
ul {
&.carets {
margin-left: 0.85em;
}
}
}
@@ -243,7 +250,7 @@ input, select, textarea {
@include border-radius($modal-content-border-radius);
}
label:not(.form-check-label):not(.btn) {
label:not(.form-check-label):not(.btn), label.bold {
font-weight: 600;
}
@@ -418,17 +425,27 @@ app-vault-groupings, app-org-vault-groupings {
display: none;
}
li {
> .fa, > div > .fa {
cursor: pointer;
}
}
li.active {
.show-active {
> .show-active, > div .show-active {
display: inline;
}
}
li.active {
a:first-child {
> a:first-of-type, > div a:first-of-type {
font-weight: bold;
color: theme-color("primary");
}
> .fa, > div > .fa {
color: theme-color("primary");
}
}
}
}

View File

@@ -5,8 +5,8 @@ import { ConstantsService } from 'jslib/services';
export class HtmlStorageService implements StorageService {
private localStorageKeys = new Set(['appId', 'anonymousAppId', 'rememberedEmail', 'passwordGenerationOptions',
ConstantsService.disableFaviconKey, ConstantsService.lockOptionKey, 'rememberEmail', 'enableGravatars',
ConstantsService.localeKey, ConstantsService.lockOptionKey]);
private localStorageStartsWithKeys = ['twoFactorToken_'];
ConstantsService.localeKey, ConstantsService.lockOptionKey, ConstantsService.autoConfirmFingerprints]);
private localStorageStartsWithKeys = ['twoFactorToken_', ConstantsService.collapsedGroupingsKey + '_'];
constructor(private platformUtilsService: PlatformUtilsService) { }

View File

@@ -107,6 +107,33 @@ export class WebPlatformUtilsService implements PlatformUtilsService {
saveFile(win: Window, blobData: any, blobOptions: any, fileName: string): void {
let blob: Blob = null;
let type: string = null;
const fileNameLower = fileName.toLowerCase();
let doDownload = true;
if (fileNameLower.endsWith('.pdf')) {
type = 'application/pdf';
doDownload = false;
} else if (fileNameLower.endsWith('.xlsx')) {
type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
} else if (fileNameLower.endsWith('.docx')) {
type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
} else if (fileNameLower.endsWith('.pptx')) {
type = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
} else if (fileNameLower.endsWith('.csv')) {
type = 'text/csv';
} else if (fileNameLower.endsWith('.png')) {
type = 'image/png';
} else if (fileNameLower.endsWith('.jpg') || fileNameLower.endsWith('.jpeg')) {
type = 'image/jpeg';
} else if (fileNameLower.endsWith('.gif')) {
type = 'image/gif';
}
if (type != null) {
blobOptions = blobOptions || {};
if (blobOptions.type == null) {
blobOptions.type = type;
}
}
if (blobOptions != null && !this.isIE()) {
blob = new Blob([blobData], blobOptions);
} else {
@@ -116,8 +143,12 @@ export class WebPlatformUtilsService implements PlatformUtilsService {
navigator.msSaveBlob(blob, fileName);
} else {
const a = win.document.createElement('a');
if (doDownload) {
a.download = fileName;
} else {
a.target = '_blank';
}
a.href = win.URL.createObjectURL(blob);
a.download = fileName;
a.style.position = 'fixed';
win.document.body.appendChild(a);
a.click();
@@ -195,9 +226,12 @@ export class WebPlatformUtilsService implements PlatformUtilsService {
contentDiv.appendChild(textDiv);
}
const confirmed = await swal({
const confirmed = buttons.length > 1 ? await swal({
content: { element: contentDiv },
buttons: buttons,
}) : await (swal as any)({
content: { element: contentDiv },
button: buttons[0],
});
return confirmed;
}