@redacto.io/consent-sdk-react 10.0.0-beta.0 → 10.0.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.turbo/turbo-build.log +22 -25
  2. package/CHANGELOG.md +123 -0
  3. package/README.md +78 -0
  4. package/dist/{chunk-6A665OPR.mjs → chunk-OGL6OC3A.mjs} +4 -0
  5. package/dist/index.d.mts +43 -8
  6. package/dist/index.d.ts +43 -8
  7. package/dist/index.js +345 -237
  8. package/dist/index.mjs +344 -238
  9. package/dist/privacy-center.d.mts +113 -37
  10. package/dist/privacy-center.d.ts +113 -37
  11. package/dist/privacy-center.js +2317 -1910
  12. package/dist/privacy-center.mjs +2245 -1835
  13. package/package.json +1 -1
  14. package/src/RedactoNoticeAssisted/RedactoNoticeAssisted.test.tsx +87 -0
  15. package/src/RedactoNoticeAssisted/RedactoNoticeAssisted.tsx +27 -0
  16. package/src/RedactoNoticeAssisted/api/index.ts +7 -1
  17. package/src/RedactoNoticeAssisted/api/types.ts +2 -0
  18. package/src/RedactoNoticeAssisted/i18n.ts +0 -55
  19. package/src/RedactoNoticeAssisted/types.ts +2 -0
  20. package/src/RedactoNoticeConsent/RedactoNoticeConsent.test.tsx +42 -8
  21. package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +75 -33
  22. package/src/RedactoNoticeConsent/api/index.ts +90 -177
  23. package/src/RedactoNoticeConsent/api/sandbox.ts +150 -0
  24. package/src/RedactoNoticeConsent/api/types.ts +60 -44
  25. package/src/RedactoNoticeConsent/language-codes.ts +0 -2
  26. package/src/RedactoNoticeConsent/types.ts +29 -3
  27. package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +86 -5
  28. package/src/RedactoNoticeConsentInline/api/index.ts +14 -5
  29. package/src/RedactoNoticeConsentInline/api/notice-read-routing.test.ts +72 -0
  30. package/src/RedactoNoticeConsentInline/api/types.ts +4 -1
  31. package/src/RedactoNoticeConsentInline/types.ts +1 -1
  32. package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +8 -5
  33. package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +38 -3
  34. package/src/RedactoPrivacyCenter/api/actions.ts +13 -5
  35. package/src/RedactoPrivacyCenter/api/client.ts +216 -39
  36. package/src/RedactoPrivacyCenter/api/fetcher.ts +24 -9
  37. package/src/RedactoPrivacyCenter/components/AppShell/AppShell.tsx +28 -0
  38. package/src/RedactoPrivacyCenter/components/AppShell/UserMenu.tsx +107 -76
  39. package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +2 -1
  40. package/src/RedactoPrivacyCenter/components/Form.tsx +53 -24
  41. package/src/RedactoPrivacyCenter/components/ModifyConsentModal.tsx +1 -1
  42. package/src/RedactoPrivacyCenter/components/SelectUser.tsx +95 -0
  43. package/src/RedactoPrivacyCenter/components/SelectUserGate.tsx +195 -0
  44. package/src/RedactoPrivacyCenter/components/constant.ts +11 -0
  45. package/src/RedactoPrivacyCenter/components/groupHelpers.ts +42 -6
  46. package/src/RedactoPrivacyCenter/context/AuthContext.tsx +131 -39
  47. package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +1 -1
  48. package/src/RedactoPrivacyCenter/context/ProfileSwitchContext.tsx +15 -0
  49. package/src/RedactoPrivacyCenter/context/types.ts +39 -1
  50. package/src/RedactoPrivacyCenter/lib/api.ts +3 -0
  51. package/src/RedactoPrivacyCenter/lib/constants.ts +12 -6
  52. package/src/RedactoPrivacyCenter/lib/locales.ts +0 -3
  53. package/src/RedactoPrivacyCenter/lib/sandbox.ts +104 -0
  54. package/src/RedactoPrivacyCenter/lib/types.ts +78 -2
  55. package/src/RedactoPrivacyCenter/lib/utils.ts +15 -0
  56. package/src/RedactoPrivacyCenter/locales/as/translation.json +7 -1
  57. package/src/RedactoPrivacyCenter/locales/bn/translation.json +7 -1
  58. package/src/RedactoPrivacyCenter/locales/brx/translation.json +7 -1
  59. package/src/RedactoPrivacyCenter/locales/doi/translation.json +7 -1
  60. package/src/RedactoPrivacyCenter/locales/en/translation.json +8 -1
  61. package/src/RedactoPrivacyCenter/locales/gom/translation.json +7 -1
  62. package/src/RedactoPrivacyCenter/locales/gu/translation.json +7 -1
  63. package/src/RedactoPrivacyCenter/locales/hi/translation.json +7 -1
  64. package/src/RedactoPrivacyCenter/locales/kn/translation.json +7 -1
  65. package/src/RedactoPrivacyCenter/locales/ks/translation.json +7 -1
  66. package/src/RedactoPrivacyCenter/locales/mai/translation.json +7 -1
  67. package/src/RedactoPrivacyCenter/locales/ml/translation.json +7 -1
  68. package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +7 -1
  69. package/src/RedactoPrivacyCenter/locales/mr/translation.json +7 -1
  70. package/src/RedactoPrivacyCenter/locales/ne/translation.json +7 -1
  71. package/src/RedactoPrivacyCenter/locales/or/translation.json +7 -1
  72. package/src/RedactoPrivacyCenter/locales/pa/translation.json +7 -1
  73. package/src/RedactoPrivacyCenter/locales/sa/translation.json +7 -1
  74. package/src/RedactoPrivacyCenter/locales/sat/translation.json +7 -1
  75. package/src/RedactoPrivacyCenter/locales/sd/translation.json +7 -1
  76. package/src/RedactoPrivacyCenter/locales/ta/translation.json +7 -1
  77. package/src/RedactoPrivacyCenter/locales/te/translation.json +7 -1
  78. package/src/RedactoPrivacyCenter/locales/ur/translation.json +7 -1
  79. package/src/RedactoPrivacyCenter/styles/injectStyles.ts +112 -2
  80. package/src/RedactoPrivacyCenter/styles/pcStyles.ts +17 -0
  81. package/src/RedactoPrivacyCenter/ui/PCAvatar.test.tsx +83 -0
  82. package/src/RedactoPrivacyCenter/ui/PCAvatar.tsx +33 -9
  83. package/src/shared/notice-consent-status.ts +190 -0
  84. package/src/shared/sandbox.ts +6 -0
  85. package/tests/Form.test.tsx +190 -7
  86. package/tests/RevokeWarningMessage.test.tsx +151 -0
  87. package/tests/consentClient.test.ts +217 -0
  88. package/tests/manageConsentServer.test.ts +38 -0
  89. package/src/RedactoPrivacyCenter/locales/bho/translation.json +0 -334
@@ -2,7 +2,6 @@
2
2
  import enTranslation from '../locales/en/translation.json';
3
3
  import asTranslation from '../locales/as/translation.json';
4
4
  import bnTranslation from '../locales/bn/translation.json';
5
- import bhoTranslation from '../locales/bho/translation.json';
6
5
  import brxTranslation from '../locales/brx/translation.json';
7
6
  import doiTranslation from '../locales/doi/translation.json';
8
7
  import gomTranslation from '../locales/gom/translation.json';
@@ -28,7 +27,6 @@ const activityFetchErrorTranslations: Record<string, string> = {
28
27
  en: 'Failed to fetch activity data',
29
28
  as: 'কাৰ্যকলাপৰ তথ্য আনিবলৈ ব্যৰ্থ',
30
29
  bn: 'কার্যকলাপের ডেটা আনতে ব্যর্থ',
31
- bho: 'गतिविधि डेटा लावे में विफल',
32
30
  brx: 'खामानि डाटा लाङो दिहुनायाव असफल',
33
31
  doi: 'गतिविधि डेटा लावै मे असफल',
34
32
  gom: 'क्रियाकलाप डेटा आणपांत अयशस्वी',
@@ -68,7 +66,6 @@ const translations: Record<string, Record<string, any>> = {
68
66
  en: { translation: withSharedActivityErrors('en', enTranslation) },
69
67
  as: { translation: withSharedActivityErrors('as', asTranslation) },
70
68
  bn: { translation: withSharedActivityErrors('bn', bnTranslation) },
71
- bho: { translation: withSharedActivityErrors('bho', bhoTranslation) },
72
69
  brx: { translation: withSharedActivityErrors('brx', brxTranslation) },
73
70
  doi: { translation: withSharedActivityErrors('doi', doiTranslation) },
74
71
  gom: { translation: withSharedActivityErrors('gom', gomTranslation) },
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Sandbox-mode singleton for the Privacy Center consent PoC.
3
+ *
4
+ * The Privacy Center resolves org/workspace/subject from the JWT into
5
+ * sessionStorage and gates every fetch behind an OTP-refresh loop. Sandbox mode
6
+ * bypasses all of that: a pasted static token plus an explicit test subject and
7
+ * org/workspace. Because the Privacy Center is a single instance per page (the
8
+ * same assumption the OTP refresh circuit breaker in `utils.ts` already makes),
9
+ * the sandbox config lives in one module-level slot that `AuthProvider`
10
+ * configures on mount and the fetch/auth layers read.
11
+ *
12
+ * When configured:
13
+ * - `syncJwtDataToSessionStorage` seeds sessionStorage from these fields
14
+ * instead of decoding the JWT,
15
+ * - `ensureValidToken` / `checkAndRefreshAuth` return the static token without
16
+ * ever calling `/otp/refresh`,
17
+ * - `privacyCenterApiFetch` sends the single `X-Consent-Token` header instead
18
+ * of `Authorization: Bearer` (its presence marks the request as
19
+ * `environment=test`). There is no subject header — the acting identity
20
+ * travels in the request's own payload: query params (`primary_email` /
21
+ * `primary_mobile`) on GET/query reads, and the body on POSTs. See
22
+ * `sandboxAuthHeaders` / `sandboxQueryIdentity` / `sandboxBodyIdentity` /
23
+ * `sandboxContact`.
24
+ */
25
+
26
+ import { SANDBOX_TOKEN_HEADER } from '../../shared/sandbox';
27
+ import type { SandboxConfig, SandboxIdentityPayload } from './types';
28
+
29
+ export { SANDBOX_TOKEN_HEADER };
30
+ export type { SandboxConfig };
31
+
32
+ let sandboxConfig: SandboxConfig | null = null;
33
+
34
+ /**
35
+ * Set (or clear, with `null`) the active sandbox configuration. Called by
36
+ * `AuthProvider` when the sandbox token prop is present. Idempotent.
37
+ */
38
+ export const setSandboxConfig = (config: SandboxConfig | null): void => {
39
+ sandboxConfig = config;
40
+ };
41
+
42
+ /** The active sandbox config, or null when sandbox mode is off. */
43
+ export const getSandboxConfig = (): SandboxConfig | null => sandboxConfig;
44
+
45
+ /** True when the Privacy Center is running in sandbox mode. */
46
+ export const isSandboxMode = (): boolean => sandboxConfig !== null;
47
+
48
+ /**
49
+ * Auth headers for a Privacy Center request in sandbox mode, or null when
50
+ * sandbox mode is off (so the caller falls back to `Authorization: Bearer`).
51
+ * Only the `X-Consent-Token` credential is sent; its presence marks the request
52
+ * as `environment=test`. There is no subject header — the acting identity
53
+ * travels in the request's own payload: query params on GET/query reads (see
54
+ * {@link sandboxQueryIdentity}) and the body on POSTs (see
55
+ * {@link sandboxBodyIdentity} / {@link sandboxContact}).
56
+ */
57
+ export const sandboxAuthHeaders = (): Record<string, string> | null => {
58
+ if (!sandboxConfig) {
59
+ return null;
60
+ }
61
+ return {
62
+ [SANDBOX_TOKEN_HEADER]: sandboxConfig.token,
63
+ };
64
+ };
65
+
66
+ /**
67
+ * The identity payload fragment for the active sandbox acting principal:
68
+ * `{ org_user_id }` when a UCIC is set (it takes precedence), else
69
+ * `{ primary_email }` when the subject looks like an email (contains "@"),
70
+ * otherwise `{ primary_mobile }`. Null when sandbox mode is off. Merge this into
71
+ * a JSON request body (POST) so the server can resolve the acting test identity.
72
+ */
73
+ export const sandboxBodyIdentity = (): SandboxIdentityPayload | null => {
74
+ if (!sandboxConfig) {
75
+ return null;
76
+ }
77
+ if (sandboxConfig.ucic) {
78
+ return { org_user_id: sandboxConfig.ucic };
79
+ }
80
+ return sandboxConfig.subject.includes('@')
81
+ ? { primary_email: sandboxConfig.subject }
82
+ : { primary_mobile: sandboxConfig.subject };
83
+ };
84
+
85
+ /**
86
+ * The identity query fragment for the active sandbox acting principal:
87
+ * `{ org_user_id }` when a UCIC is set (it takes precedence), else
88
+ * `{ primary_email }` when the subject looks like an email (contains "@"),
89
+ * otherwise `{ primary_mobile }`. Null when sandbox mode is off. Append these to
90
+ * a GET/query request's query string so the server can resolve the acting test
91
+ * identity (it reads `org_user_id` / `primary_email` / `primary_mobile` query
92
+ * params on sandbox reads).
93
+ */
94
+ export const sandboxQueryIdentity = (): SandboxIdentityPayload | null =>
95
+ sandboxBodyIdentity();
96
+
97
+ /**
98
+ * The raw sandbox contact string, for endpoints whose server field is a single
99
+ * `contact` (the server classifies it as email/phone/UCIC) — create-case,
100
+ * manage-consent. Prefers the UCIC over the email/mobile subject. Null when
101
+ * sandbox mode is off.
102
+ */
103
+ export const sandboxContact = (): string | null =>
104
+ sandboxConfig ? sandboxConfig.ucic || sandboxConfig.subject : null;
@@ -1,3 +1,19 @@
1
+ export type SandboxConfig = Readonly<{
2
+ token: string;
3
+ /** UCIC — the client's own user id (`org_user_id`). Takes precedence over `subject`. */
4
+ ucic?: string;
5
+ subject: string;
6
+ organisationUuid: string;
7
+ workspaceUuid: string;
8
+ slug: string;
9
+ }>;
10
+
11
+ /** The identity payload fragment for the sandbox acting principal. */
12
+ export type SandboxIdentityPayload =
13
+ | { org_user_id: string }
14
+ | { primary_email: string }
15
+ | { primary_mobile: string };
16
+
1
17
  export type Workspace = {
2
18
  uuid: string;
3
19
  suid: string;
@@ -248,6 +264,10 @@ export type NominatorInfo = {
248
264
 
249
265
  export type PurposeItem = {
250
266
  purpose_uuid: string;
267
+ // Alias emitted by the legacy Python user-consents payload, which keys some
268
+ // purposes as `uuid` instead of `purpose_uuid`. Optional: the Go ledger
269
+ // always sends `purpose_uuid`.
270
+ uuid?: string;
251
271
  name: string;
252
272
  description: string | null;
253
273
  status: ConsentStatusEnum | string;
@@ -256,6 +276,11 @@ export type PurposeItem = {
256
276
  method: string;
257
277
  data_elements: ConsentDataElement[];
258
278
  link_reason: string | null;
279
+ // Per-purpose override for the revoke-confirmation warning message. When set,
280
+ // the revoke modal shows this text instead of the localized default; when
281
+ // null/empty/absent, the default `revokeConsentWarning` copy is used.
282
+ // Optional for backwards-compat: older backends omit it.
283
+ revoke_warning_message?: string | null;
259
284
  // UUID of the notice version this purpose was consented under. Served by the
260
285
  // Go ledger's user-consents response; required to revoke/regrant via the
261
286
  // ledger's submit-consent endpoint (which has no manage-consent route).
@@ -349,6 +374,12 @@ export type ManageConsentResponse = {
349
374
  };
350
375
  };
351
376
 
377
+ // Unwrapped `detail` of the legacy Python manage-consent response; the Go
378
+ // ledger returns a ConsentEventResponse with no `success` flag instead.
379
+ export type LegacyManageConsentResponse = {
380
+ success: boolean;
381
+ };
382
+
352
383
  export type ManageConsentParams = {
353
384
  organizationId: string;
354
385
  workspaceId: string;
@@ -411,8 +442,10 @@ export type Receipt = {
411
442
 
412
443
  // Mirrors the Go ledger's `ConsentReceiptListResponse` (offset-paginated page
413
444
  // of the principal's receipts): flat `total`/`skip`/`limit`, not a nested
414
- // `pagination` object. `normalizeReceipts` in ReceiptsList tolerates either
415
- // envelope, but this type documents the ledger contract the SDK now calls.
445
+ // `pagination` object. Without a configured ledgerBaseUrl the legacy Python
446
+ // list is called instead, which returns a `{ data, pagination }` envelope —
447
+ // `normalizeReceipts` in ReceiptsList tolerates either shape; this type
448
+ // documents the ledger contract.
416
449
  export type ReceiptListResponse = {
417
450
  data: Receipt[];
418
451
  total: number;
@@ -814,3 +847,46 @@ export type NotificationRefreshButtonProps = Readonly<{
814
847
  onRefresh: () => void;
815
848
  iconSize?: number;
816
849
  }>;
850
+
851
+ export type IdentityCandidate = Readonly<{
852
+ uuid: string;
853
+ org_user_id?: string | null;
854
+ primary_email?: string | null;
855
+ primary_mobile?: string | null;
856
+ created_at?: string | null;
857
+ }>;
858
+
859
+ export type IdentityListResponse = Readonly<{
860
+ identities: IdentityCandidate[];
861
+ }>;
862
+
863
+ export type SelectPrincipalResponse = Readonly<{
864
+ token: string;
865
+ refresh_token: string;
866
+ expires_at?: string;
867
+ }>;
868
+
869
+ // Discrete phases of the shared-contact profile gate: `checking` probes the
870
+ // backend for sibling principals, `picking` shows the profile picker, and
871
+ // `resolved` passes through to children.
872
+ export type GatePhase = 'checking' | 'picking' | 'resolved';
873
+
874
+ export type SelectUserProps = Readonly<{
875
+ candidates: IdentityCandidate[];
876
+ onSelect: (orgUserId: string) => void;
877
+ busyOrgUserId: string | null;
878
+ error?: string | null;
879
+ }>;
880
+
881
+ export type SelectUserGateProps = Readonly<{
882
+ children: React.ReactNode;
883
+ }>;
884
+
885
+ // Exposed by SelectUserGate so a signed-in session can re-open the profile
886
+ // picker (shared contact). `canSwitch` is true only when the contact maps to
887
+ // more than one principal; `switchProfile` drops the pinned choice and shows
888
+ // the picker again.
889
+ export type ProfileSwitchValue = Readonly<{
890
+ canSwitch: boolean;
891
+ switchProfile: () => void;
892
+ }>;
@@ -1,5 +1,6 @@
1
1
  import { refreshOtpTokenServer } from './api';
2
2
  import { isTerminalRefreshError } from '../api/fetcher';
3
+ import { getSandboxConfig } from './sandbox';
3
4
  import {
4
5
  MIN_REFRESH_BACKOFF_MS,
5
6
  MAX_REFRESH_BACKOFF_MS,
@@ -373,6 +374,12 @@ export const checkAndRefreshAuth = async (
373
374
  ): Promise<boolean> => {
374
375
  if (typeof window === 'undefined') return false;
375
376
 
377
+ // Sandbox PoC: the static token is always "valid" and there is nothing to
378
+ // refresh, so authentication is satisfied unconditionally.
379
+ if (getSandboxConfig()) {
380
+ return true;
381
+ }
382
+
376
383
  const accessToken = sessionStorage.getItem('access_token');
377
384
  const email = sessionStorage.getItem('email');
378
385
  const orgSlug = sessionStorage.getItem('pc_org_slug');
@@ -555,6 +562,14 @@ export const ensureValidToken = async (
555
562
  ): Promise<string | null> => {
556
563
  if (typeof window === 'undefined') return null;
557
564
 
565
+ // Sandbox PoC: no JWT, no expiry, no refresh — hand back the static token so
566
+ // callers proceed straight to the request (which carries the X-Consent-Token
567
+ // header instead of Authorization, and the acting identity in its payload).
568
+ const sandbox = getSandboxConfig();
569
+ if (sandbox) {
570
+ return sandbox.token;
571
+ }
572
+
558
573
  // Use context accessToken if provided, otherwise fall back to sessionStorage
559
574
  const accessToken = authContext?.accessToken || sessionStorage.getItem('access_token');
560
575
 
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "প্ৰ'ফাইল সলনি কৰক",
335
+ "chooseYourProfile": "আপোনাৰ প্ৰ'ফাইল বাছনি কৰক",
336
+ "loginIdentifierLinkedToMultipleProfiles": "লগইন আইডি একাধিক প্ৰ'ফাইলৰ সৈতে সংযুক্ত। আপুনি চাব বিচৰাটো বাছনি কৰক।",
337
+ "signingInEllipsis": "ছাইন ইন হৈ আছে…",
338
+ "couldNotSwitchProfile": "সেই প্ৰ'ফাইললৈ সলনি কৰিব পৰা নগ'ল। অনুগ্ৰহ কৰি পুনৰ চেষ্টা কৰক।",
339
+ "userIdLabel": "ব্যৱহাৰকাৰী আইডি: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "প্রোফাইল পরিবর্তন করুন",
335
+ "chooseYourProfile": "আপনার প্রোফাইল বেছে নিন",
336
+ "loginIdentifierLinkedToMultipleProfiles": "লগইন আইডি একাধিক প্রোফাইলের সাথে যুক্ত। আপনি যেটি দেখতে চান সেটি বেছে নিন।",
337
+ "signingInEllipsis": "সাইন ইন হচ্ছে…",
338
+ "couldNotSwitchProfile": "সেই প্রোফাইলে স্যুইচ করা যায়নি। অনুগ্রহ করে আবার চেষ্টা করুন।",
339
+ "userIdLabel": "ব্যবহারকারীর আইডি: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "प्रोफाइल सोलाय",
335
+ "chooseYourProfile": "नोंथांनि प्रफाइल सायख",
336
+ "loginIdentifierLinkedToMultipleProfiles": "लॉगिन आईडी मोनसेनिख्रुइ बांसिन प्रफाइलजों नांजाब दं। नोंथाङा नायनो लुबैयोब्ला बेखौ सायख।",
337
+ "signingInEllipsis": "साइन इन जायगासिनो दं…",
338
+ "couldNotSwitchProfile": "बै प्रफाइलआव स्विच खालामनो हायाखै। अननानै फिन नाजा।",
339
+ "userIdLabel": "यूजर आईडी: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "प्रोफाइल बदलो",
335
+ "chooseYourProfile": "अपनी प्रोफाइल चुनो",
336
+ "loginIdentifierLinkedToMultipleProfiles": "लॉगिन आईडी इक कोला मता प्रोफाइलें कन्नै जुड़्या दा ऐ। जेह्ड़ी तुसें दिक्खनी ऐ ओह् चुनो।",
337
+ "signingInEllipsis": "साइन इन होआ करदा ऐ…",
338
+ "couldNotSwitchProfile": "ओह् प्रोफाइल पर स्विच नेईं होई सकेआ। कृपा करियै दुबारा कोशिश करो।",
339
+ "userIdLabel": "प्रयोगकर्ता आईडी: {{id}}"
334
340
  }
@@ -344,5 +344,12 @@
344
344
  "forProduct": "For {{productName}}",
345
345
  "actingOnBehalfOfShort": "acting on behalf of {{nominator}}",
346
346
  "nominationChipSuffix": "· {{nominator}}",
347
- "selectPurposesForThisProduct": "Select purposes within this product."
347
+ "selectPurposesForThisProduct": "Select purposes within this product.",
348
+ "switchProfile": "Switch profile",
349
+ "chooseYourProfile": "Choose your profile",
350
+ "loginIdentifierLinkedToMultipleProfiles": "The login identifier is linked to more than one profile. Choose the one you want to view.",
351
+ "signingInEllipsis": "Signing in…",
352
+ "couldNotSwitchProfile": "Could not switch to that profile. Please try again.",
353
+ "userIdLabel": "User ID: {{id}}",
354
+ "accountMenu": "Account menu"
348
355
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "प्रोफायल बदला",
335
+ "chooseYourProfile": "तुमचें प्रोफायल निवडात",
336
+ "loginIdentifierLinkedToMultipleProfiles": "लॉगिन आयडी एकापरस चड प्रोफायलांक जोडला. तुमकां जें पळोवपाक जाय तें निवडात.",
337
+ "signingInEllipsis": "साइन इन जावन आसा…",
338
+ "couldNotSwitchProfile": "त्या प्रोफायलाचेर स्विच करूंक जालें ना. उपकार करून परत यत्न करात.",
339
+ "userIdLabel": "वापरपी आयडी: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "પ્રોફાઇલ બદલો",
335
+ "chooseYourProfile": "તમારી પ્રોફાઇલ પસંદ કરો",
336
+ "loginIdentifierLinkedToMultipleProfiles": "લોગિન આઈડી એક કરતાં વધુ પ્રોફાઇલ સાથે જોડાયેલ છે. તમે જે જોવા માંગો છો તે પસંદ કરો.",
337
+ "signingInEllipsis": "સાઇન ઇન થઈ રહ્યું છે…",
338
+ "couldNotSwitchProfile": "તે પ્રોફાઇલ પર સ્વિચ કરી શકાયું નહીં. કૃપા કરીને ફરી પ્રયાસ કરો.",
339
+ "userIdLabel": "વપરાશકર્તા આઈડી: {{id}}"
334
340
  }
@@ -333,5 +333,11 @@
333
333
  "casesCreatedCount_other": "{{count}} cases created",
334
334
  "someRequestsFailed": "Some requests failed",
335
335
  "retry": "Retry",
336
- "retrying": "Retrying..."
336
+ "retrying": "Retrying...",
337
+ "switchProfile": "प्रोफ़ाइल बदलें",
338
+ "chooseYourProfile": "अपनी प्रोफ़ाइल चुनें",
339
+ "loginIdentifierLinkedToMultipleProfiles": "लॉगिन आईडी एक से अधिक प्रोफ़ाइल से जुड़ा है। जिसे आप देखना चाहते हैं उसे चुनें।",
340
+ "signingInEllipsis": "साइन इन हो रहा है…",
341
+ "couldNotSwitchProfile": "उस प्रोफ़ाइल पर स्विच नहीं किया जा सका। कृपया पुनः प्रयास करें।",
342
+ "userIdLabel": "उपयोगकर्ता आईडी: {{id}}"
337
343
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "ಪ್ರೊಫೈಲ್ ಬದಲಾಯಿಸಿ",
335
+ "chooseYourProfile": "ನಿಮ್ಮ ಪ್ರೊಫೈಲ್ ಆಯ್ಕೆಮಾಡಿ",
336
+ "loginIdentifierLinkedToMultipleProfiles": "ಲಾಗಿನ್ ಐಡಿ ಒಂದಕ್ಕಿಂತ ಹೆಚ್ಚು ಪ್ರೊಫೈಲ್‌ಗಳಿಗೆ ಲಿಂಕ್ ಆಗಿದೆ. ನೀವು ವೀಕ್ಷಿಸಲು ಬಯಸುವುದನ್ನು ಆಯ್ಕೆಮಾಡಿ.",
337
+ "signingInEllipsis": "ಸೈನ್ ಇನ್ ಆಗುತ್ತಿದೆ…",
338
+ "couldNotSwitchProfile": "ಆ ಪ್ರೊಫೈಲ್‌ಗೆ ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ದಯವಿಟ್ಟು ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.",
339
+ "userIdLabel": "ಬಳಕೆದಾರ ಐಡಿ: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "پروفائل بدلاو",
335
+ "chooseYourProfile": "پننہٕ پروفائل ژارٕو",
336
+ "loginIdentifierLinkedToMultipleProfiles": "لاگ اِن آئی ڈی چھُ اکہ کھۄتہ زیادٕ پروفائلن سٟتؠ جوڑنہ آمُت۔ یُس توہہِ وُچھُن چھِو یژھان سُ ژارٕو۔",
337
+ "signingInEllipsis": "سائن اِن گژھان چھُ…",
338
+ "couldNotSwitchProfile": "تہِ پروفائلس منٛز سوِچ کرُن آو نہ۔ مہربانی کرِتھ دوبارٕ کوشش کریو۔",
339
+ "userIdLabel": "صارف آئی ڈی: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "प्रोफाइल बदलू",
335
+ "chooseYourProfile": "अपन प्रोफाइल चुनू",
336
+ "loginIdentifierLinkedToMultipleProfiles": "लॉगिन आइडी एकाधिक प्रोफाइलसँ जुड़ल अछि। जे अहाँ देखय चाहैत छी ओकरा चुनू।",
337
+ "signingInEllipsis": "साइन इन भ' रहल अछि…",
338
+ "couldNotSwitchProfile": "ओ प्रोफाइल पर स्विच नहि भ' सकल। कृपया फेर सँ प्रयास करू।",
339
+ "userIdLabel": "उपयोगकर्ता आइडी: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "പ്രൊഫൈൽ മാറ്റുക",
335
+ "chooseYourProfile": "നിങ്ങളുടെ പ്രൊഫൈൽ തിരഞ്ഞെടുക്കുക",
336
+ "loginIdentifierLinkedToMultipleProfiles": "ലോഗിൻ ഐഡി ഒന്നിലധികം പ്രൊഫൈലുകളുമായി ബന്ധിപ്പിച്ചിരിക്കുന്നു. നിങ്ങൾ കാണാൻ ആഗ്രഹിക്കുന്നത് തിരഞ്ഞെടുക്കുക.",
337
+ "signingInEllipsis": "സൈൻ ഇൻ ചെയ്യുന്നു…",
338
+ "couldNotSwitchProfile": "ആ പ്രൊഫൈലിലേക്ക് മാറാൻ കഴിഞ്ഞില്ല. വീണ്ടും ശ്രമിക്കുക.",
339
+ "userIdLabel": "ഉപയോക്തൃ ഐഡി: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "প্রোফাইল হোংদোক-উ",
335
+ "chooseYourProfile": "নহাক্কী প্রোফাইল খনবিয়ু",
336
+ "loginIdentifierLinkedToMultipleProfiles": "লগইন আইডি অসি প্রোফাইল অমদগী হেন্না লোইননবা লৈ। নহাক্না য়েংনিংবা অদু খনবিয়ু।",
337
+ "signingInEllipsis": "সাইন ইন তৌরি…",
338
+ "couldNotSwitchProfile": "প্রোফাইল অদুদা হোংদোকপা ঙমদ্রে। চানবীদুনা অমুক হন্না হোৎনবিয়ু।",
339
+ "userIdLabel": "ꯃꯤꯑꯣꯏꯕ ꯑꯥꯏꯗꯤ: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "प्रोफाइल बदला",
335
+ "chooseYourProfile": "तुमची प्रोफाइल निवडा",
336
+ "loginIdentifierLinkedToMultipleProfiles": "लॉगिन आयडी एकापेक्षा जास्त प्रोफाइलशी जोडलेला आहे. तुम्हाला जी पाहायची आहे ती निवडा.",
337
+ "signingInEllipsis": "साइन इन करत आहे…",
338
+ "couldNotSwitchProfile": "त्या प्रोफाइलवर स्विच करता आले नाही. कृपया पुन्हा प्रयत्न करा.",
339
+ "userIdLabel": "वापरकर्ता आयडी: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "प्रोफाइल बदल्नुहोस्",
335
+ "chooseYourProfile": "आफ्नो प्रोफाइल छान्नुहोस्",
336
+ "loginIdentifierLinkedToMultipleProfiles": "लगइन आईडी एकभन्दा बढी प्रोफाइलसँग जोडिएको छ। तपाईंले हेर्न चाहनुभएको छान्नुहोस्।",
337
+ "signingInEllipsis": "साइन इन हुँदैछ…",
338
+ "couldNotSwitchProfile": "त्यो प्रोफाइलमा स्विच गर्न सकिएन। कृपया फेरि प्रयास गर्नुहोस्।",
339
+ "userIdLabel": "प्रयोगकर्ता आईडी: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "ପ୍ରୋଫାଇଲ୍ ବଦଳାନ୍ତୁ",
335
+ "chooseYourProfile": "ଆପଣଙ୍କ ପ୍ରୋଫାଇଲ୍ ବାଛନ୍ତୁ",
336
+ "loginIdentifierLinkedToMultipleProfiles": "ଲଗଇନ୍ ଆଇଡି ଏକାଧିକ ପ୍ରୋଫାଇଲ୍ ସହିତ ଯୋଡ଼ାଯାଇଛି। ଆପଣ ଦେଖିବାକୁ ଚାହୁଁଥିବାଟି ବାଛନ୍ତୁ।",
337
+ "signingInEllipsis": "ସାଇନ୍ ଇନ୍ ହେଉଛି…",
338
+ "couldNotSwitchProfile": "ସେହି ପ୍ରୋଫାଇଲକୁ ସ୍ୱିଚ୍ କରାଯାଇପାରିଲା ନାହିଁ। ଦୟାକରି ପୁନର୍ବାର ଚେଷ୍ଟା କରନ୍ତୁ।",
339
+ "userIdLabel": "ବ୍ୟବହାରକାରୀ ଆଇଡି: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "ਪ੍ਰੋਫਾਈਲ ਬਦਲੋ",
335
+ "chooseYourProfile": "ਆਪਣੀ ਪ੍ਰੋਫਾਈਲ ਚੁਣੋ",
336
+ "loginIdentifierLinkedToMultipleProfiles": "ਲੌਗਇਨ ਆਈਡੀ ਇੱਕ ਤੋਂ ਵੱਧ ਪ੍ਰੋਫਾਈਲਾਂ ਨਾਲ ਜੁੜਿਆ ਹੋਇਆ ਹੈ। ਜੋ ਤੁਸੀਂ ਵੇਖਣਾ ਚਾਹੁੰਦੇ ਹੋ ਉਹ ਚੁਣੋ।",
337
+ "signingInEllipsis": "ਸਾਈਨ ਇਨ ਹੋ ਰਿਹਾ ਹੈ…",
338
+ "couldNotSwitchProfile": "ਉਸ ਪ੍ਰੋਫਾਈਲ 'ਤੇ ਸਵਿੱਚ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।",
339
+ "userIdLabel": "ਉਪਯੋਗਕਰਤਾ ਆਈਡੀ: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "प्रोफ़ाइलं परिवर्तयतु",
335
+ "chooseYourProfile": "स्वप्रोफ़ाइलं चिनोतु",
336
+ "loginIdentifierLinkedToMultipleProfiles": "प्रवेश-आयडी एकाधिकैः प्रोफ़ाइलैः सह सम्बद्धः अस्ति। यत् द्रष्टुम् इच्छति तत् चिनोतु।",
337
+ "signingInEllipsis": "प्रवेशः क्रियते…",
338
+ "couldNotSwitchProfile": "तां प्रोफ़ाइलं प्रति परिवर्तनं न शक्यते स्म। कृपया पुनः प्रयत्नं करोतु।",
339
+ "userIdLabel": "उपयोक्तृ-आयडी: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "ᱯᱨᱳᱯᱷᱟᱭᱤᱞ ᱵᱚᱫᱚᱞ ᱢᱮ",
335
+ "chooseYourProfile": "ᱟᱢᱟᱜ ᱯᱨᱳᱯᱷᱟᱭᱤᱞ ᱵᱟᱪᱷᱟᱣ ᱢᱮ",
336
+ "loginIdentifierLinkedToMultipleProfiles": "ᱞᱚᱜᱤᱱ ᱟᱭᱰᱤ ᱫᱚ ᱢᱤᱫ ᱠᱷᱚᱱ ᱰᱷᱮᱨ ᱯᱨᱳᱯᱷᱟᱭᱤᱞ ᱥᱟᱶ ᱡᱩᱰᱟᱹᱣ ᱟᱠᱟᱱᱟ᱾ ᱟᱢ ᱧᱮᱞ ᱥᱟᱱᱟᱢ ᱚᱱᱟ ᱵᱟᱪᱷᱟᱣ ᱢᱮ᱾",
337
+ "signingInEllipsis": "ᱥᱟᱭᱤᱱ ᱤᱱ ᱮᱫᱟᱭ…",
338
+ "couldNotSwitchProfile": "ᱚᱱᱟ ᱯᱨᱳᱯᱷᱟᱭᱤᱞ ᱛᱮ ᱥᱩᱭᱪ ᱵᱟᱝ ᱦᱩᱭ ᱞᱮᱱᱟ᱾ ᱫᱟᱭᱟ ᱠᱟᱛᱮ ᱫᱩᱠᱟᱹᱛᱮ ᱠᱩᱨᱩᱢᱩᱴᱩ ᱢᱮ᱾",
339
+ "userIdLabel": "ᱵᱮᱵᱷᱟᱨᱤᱭᱟᱹ ᱟᱭᱰᱤ: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "پروفائل تبديل ڪريو",
335
+ "chooseYourProfile": "پنهنجو پروفائل چونڊيو",
336
+ "loginIdentifierLinkedToMultipleProfiles": "لاگ ان آئيڊي هڪ کان وڌيڪ پروفائلن سان ڳنڍيل آهي. جيڪو توهان ڏسڻ چاهيو ٿا اهو چونڊيو.",
337
+ "signingInEllipsis": "سائن ان ٿي رهيو آهي…",
338
+ "couldNotSwitchProfile": "ان پروفائل تي سوئچ نه ٿي سگهيو. مهرباني ڪري ٻيهر ڪوشش ڪريو.",
339
+ "userIdLabel": "يوزر آئيڊي: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "சுயவிவரத்தை மாற்று",
335
+ "chooseYourProfile": "உங்கள் சுயவிவரத்தைத் தேர்ந்தெடுக்கவும்",
336
+ "loginIdentifierLinkedToMultipleProfiles": "உள்நுழைவு ஐடி ஒன்றுக்கு மேற்பட்ட சுயவிவரங்களுடன் இணைக்கப்பட்டுள்ளது. நீங்கள் பார்க்க விரும்புவதைத் தேர்ந்தெடுக்கவும்.",
337
+ "signingInEllipsis": "உள்நுழைகிறது…",
338
+ "couldNotSwitchProfile": "அந்தச் சுயவிவரத்திற்கு மாற முடியவில்லை. மீண்டும் முயற்சிக்கவும்.",
339
+ "userIdLabel": "பயனர் ஐடி: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "ప్రొఫైల్‌ను మార్చండి",
335
+ "chooseYourProfile": "మీ ప్రొఫైల్‌ను ఎంచుకోండి",
336
+ "loginIdentifierLinkedToMultipleProfiles": "లాగిన్ ఐడి ఒకటి కంటే ఎక్కువ ప్రొఫైల్‌లతో అనుసంధానించబడింది. మీరు చూడాలనుకుంటున్నదాన్ని ఎంచుకోండి.",
337
+ "signingInEllipsis": "సైన్ ఇన్ అవుతోంది…",
338
+ "couldNotSwitchProfile": "ఆ ప్రొఫైల్‌కు మారడం సాధ్యం కాలేదు. దయచేసి మళ్లీ ప్రయత్నించండి.",
339
+ "userIdLabel": "వినియోగదారు ఐడి: {{id}}"
334
340
  }
@@ -330,5 +330,11 @@
330
330
  "casesCreatedCount_other": "{{count}} cases created",
331
331
  "someRequestsFailed": "Some requests failed",
332
332
  "retry": "Retry",
333
- "retrying": "Retrying..."
333
+ "retrying": "Retrying...",
334
+ "switchProfile": "پروفائل تبدیل کریں",
335
+ "chooseYourProfile": "اپنی پروفائل منتخب کریں",
336
+ "loginIdentifierLinkedToMultipleProfiles": "لاگ ان آئی ڈی ایک سے زیادہ پروفائلز سے منسلک ہے۔ جسے آپ دیکھنا چاہتے ہیں اسے منتخب کریں۔",
337
+ "signingInEllipsis": "سائن ان ہو رہا ہے…",
338
+ "couldNotSwitchProfile": "اس پروفائل پر سوئچ نہیں کیا جا سکا۔ براہ کرم دوبارہ کوشش کریں۔",
339
+ "userIdLabel": "صارف آئی ڈی: {{id}}"
334
340
  }