@brumaombra/ui-vintage 0.8.0 → 0.8.1
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.
- package/COMPONENTS.md +42 -1
- package/README.md +1 -1
- package/package.json +2 -1
- package/src/components/cookie-consent/CookieConsent.vue +82 -0
- package/src/components/cookie-consent/index.ts +3 -0
- package/src/components/cookie-consent/useCookieConsent.ts +55 -0
- package/src/components/ui/animated-number/AnimatedNumber.vue +19 -5
- package/src/i18n/de.json +7 -0
- package/src/i18n/en.json +7 -0
- package/src/i18n/es.json +7 -0
- package/src/i18n/fr.json +7 -0
- package/src/i18n/it.json +7 -0
- package/src/i18n/ja.json +7 -0
- package/src/i18n/pt.json +7 -0
- package/src/i18n/ru.json +7 -0
- package/src/i18n/zh.json +7 -0
package/COMPONENTS.md
CHANGED
|
@@ -20,7 +20,7 @@ This file lists every public entry point of the package with its components, pro
|
|
|
20
20
|
- **Data display:** [animated-number](#brumaombraui-vintageanimated-number), [avatar](#brumaombraui-vintageavatar), [badge](#brumaombraui-vintagebadge), [card](#brumaombraui-vintagecard), [card-grid](#brumaombraui-vintagecard-grid), [chip](#brumaombraui-vintagechip), [data-list](#brumaombraui-vintagedata-list), [data-table](#brumaombraui-vintagedata-table), [info-card](#brumaombraui-vintageinfo-card), [progress](#brumaombraui-vintageprogress), [progress-component](#brumaombraui-vintageprogress-component), [scroll-area](#brumaombraui-vintagescroll-area), [separator](#brumaombraui-vintageseparator), [single-value-card](#brumaombraui-vintagesingle-value-card), [skeleton](#brumaombraui-vintageskeleton), [table](#brumaombraui-vintagetable)
|
|
21
21
|
- **Navigation:** [accordion](#brumaombraui-vintageaccordion), [breadcrumb](#brumaombraui-vintagebreadcrumb), [collapsible](#brumaombraui-vintagecollapsible), [pagination](#brumaombraui-vintagepagination), [sidebar](#brumaombraui-vintagesidebar), [stepper](#brumaombraui-vintagestepper), [tabs](#brumaombraui-vintagetabs)
|
|
22
22
|
- **Overlays:** [alert-dialog](#brumaombraui-vintagealert-dialog), [command](#brumaombraui-vintagecommand), [dialog](#brumaombraui-vintagedialog), [hover-card](#brumaombraui-vintagehover-card), [popover](#brumaombraui-vintagepopover), [sheet](#brumaombraui-vintagesheet), [tooltip](#brumaombraui-vintagetooltip)
|
|
23
|
-
- **Feedback:** [alert](#brumaombraui-vintagealert), [busy](#brumaombraui-vintagebusy), [busy-indicator](#brumaombraui-vintagebusy-indicator), [confirm-dialog](#brumaombraui-vintageconfirm-dialog), [empty-state-card](#brumaombraui-vintageempty-state-card), [loading-state-card](#brumaombraui-vintageloading-state-card), [message-dialog](#brumaombraui-vintagemessage-dialog), [message-toast](#brumaombraui-vintagemessage-toast), [spinner](#brumaombraui-vintagespinner)
|
|
23
|
+
- **Feedback:** [alert](#brumaombraui-vintagealert), [busy](#brumaombraui-vintagebusy), [busy-indicator](#brumaombraui-vintagebusy-indicator), [confirm-dialog](#brumaombraui-vintageconfirm-dialog), [cookie-consent](#brumaombraui-vintagecookie-consent), [empty-state-card](#brumaombraui-vintageempty-state-card), [loading-state-card](#brumaombraui-vintageloading-state-card), [message-dialog](#brumaombraui-vintagemessage-dialog), [message-toast](#brumaombraui-vintagemessage-toast), [spinner](#brumaombraui-vintagespinner)
|
|
24
24
|
- **Layouts and app shell:** [background-grid](#brumaombraui-vintagebackground-grid), [dashboard-shell](#brumaombraui-vintagedashboard-shell), [error-page](#brumaombraui-vintageerror-page), [landing](#brumaombraui-vintagelanding), [landing-content](#brumaombraui-vintagelanding-content), [landing-footer](#brumaombraui-vintagelanding-footer), [landing-navbar](#brumaombraui-vintagelanding-navbar), [landing-shell](#brumaombraui-vintagelanding-shell), [language-flag](#brumaombraui-vintagelanguage-flag), [language-selector](#brumaombraui-vintagelanguage-selector), [page-header](#brumaombraui-vintagepage-header), [theme-selector](#brumaombraui-vintagetheme-selector)
|
|
25
25
|
- **Content and blog:** [blog](#brumaombraui-vintageblog), [content](#brumaombraui-vintagecontent)
|
|
26
26
|
- **Utilities and types:** [common-types](#brumaombraui-vintagecommon-types), [utils](#brumaombraui-vintageutils)
|
|
@@ -2814,6 +2814,47 @@ interface ShowConfirmDialogOptions {
|
|
|
2814
2814
|
|
|
2815
2815
|
---
|
|
2816
2816
|
|
|
2817
|
+
### `@brumaombra/ui-vintage/cookie-consent`
|
|
2818
|
+
|
|
2819
|
+
Cookie consent banner fixed to the bottom of the page, shown in the browser until the visitor accepts or declines. The choice is saved in `localStorage` under `storage-key`; `useCookieConsent(storageKey)` shares it, so optional scripts (analytics, ads) can wait for `consent.value === "granted"` and a settings page can call `reset()` to ask again. Texts have translated defaults, `policy-to` adds a link to the cookie policy.
|
|
2820
|
+
|
|
2821
|
+
```ts
|
|
2822
|
+
import { CookieConsent, useCookieConsent } from '@brumaombra/ui-vintage/cookie-consent';
|
|
2823
|
+
import type { CookieConsentValue } from '@brumaombra/ui-vintage/cookie-consent';
|
|
2824
|
+
```
|
|
2825
|
+
|
|
2826
|
+
```vue
|
|
2827
|
+
<CookieConsent storage-key="analyticsConsent" policy-to="/cookie-policy" @accept="loadAnalytics" />
|
|
2828
|
+
|
|
2829
|
+
<script setup>
|
|
2830
|
+
const { consent, reset } = useCookieConsent('analyticsConsent');
|
|
2831
|
+
watch(consent, value => value === 'granted' && loadAnalytics(), { immediate: true });
|
|
2832
|
+
</script>
|
|
2833
|
+
```
|
|
2834
|
+
|
|
2835
|
+
#### `CookieConsent`
|
|
2836
|
+
|
|
2837
|
+
| Prop | Type | Default |
|
|
2838
|
+
| --- | --- | --- |
|
|
2839
|
+
| `storageKey` | `string` | `'cookieConsent'` |
|
|
2840
|
+
| `message` | `string` | `undefined` |
|
|
2841
|
+
| `policyTo` | `string` | `undefined` |
|
|
2842
|
+
| `policyLabel` | `string` | `undefined` |
|
|
2843
|
+
| `acceptLabel` | `string` | `undefined` |
|
|
2844
|
+
| `declineLabel` | `string` | `undefined` |
|
|
2845
|
+
| `class` | `HTMLAttributes['class']` | `undefined` |
|
|
2846
|
+
|
|
2847
|
+
- **Emits:** `accept`, `decline`.
|
|
2848
|
+
|
|
2849
|
+
#### Functions, constants, and types
|
|
2850
|
+
|
|
2851
|
+
```ts
|
|
2852
|
+
function useCookieConsent(storageKey = 'cookieConsent')
|
|
2853
|
+
type CookieConsentValue = 'granted' | 'denied' | null
|
|
2854
|
+
```
|
|
2855
|
+
|
|
2856
|
+
---
|
|
2857
|
+
|
|
2817
2858
|
### `@brumaombra/ui-vintage/empty-state-card`
|
|
2818
2859
|
|
|
2819
2860
|
Empty state with an icon, title, description, and an `action` slot. Falls back to localized default copy.
|
package/README.md
CHANGED
|
@@ -358,7 +358,7 @@ There is no required library build step before publishing. The normal verificati
|
|
|
358
358
|
npm run typecheck
|
|
359
359
|
```
|
|
360
360
|
|
|
361
|
-
For release
|
|
361
|
+
For the release process, see the project skill in [`.claude/skills/publish-npm/SKILL.md`](.claude/skills/publish-npm/SKILL.md). The package is published under the public npm scope `@brumaombra/ui-vintage`.
|
|
362
362
|
|
|
363
363
|
<a id="requirements"></a>
|
|
364
364
|
## 🧰 Requirements
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brumaombra/ui-vintage",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "Source-published Nuxt UI runtime with shared theme tokens and built-in Nuxt integrations.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"author": "Mauro Brambilla",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"./command": "./src/components/ui/command/index.ts",
|
|
60
60
|
"./common-types": "./src/lib/common-types.ts",
|
|
61
61
|
"./confirm-dialog": "./src/components/confirm-dialog/index.ts",
|
|
62
|
+
"./cookie-consent": "./src/components/cookie-consent/index.ts",
|
|
62
63
|
"./content": "./src/components/content/index.ts",
|
|
63
64
|
"./dashboard-shell": "./src/components/dashboard-shell/index.ts",
|
|
64
65
|
"./data-list": "./src/components/data-list/index.ts",
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, onMounted, ref, type HTMLAttributes } from 'vue';
|
|
3
|
+
import { useI18n } from 'vue-i18n';
|
|
4
|
+
import { Button } from '../ui/button';
|
|
5
|
+
import { Card } from '../ui/card';
|
|
6
|
+
import { cn } from '../../lib/utils';
|
|
7
|
+
import { useCookieConsent } from './useCookieConsent';
|
|
8
|
+
|
|
9
|
+
// Extra attributes go on the banner (the root is the Teleport)
|
|
10
|
+
defineOptions({ inheritAttrs: false });
|
|
11
|
+
|
|
12
|
+
// Props
|
|
13
|
+
const props = withDefaults(defineProps<{
|
|
14
|
+
storageKey?: string;
|
|
15
|
+
message?: string;
|
|
16
|
+
policyTo?: string;
|
|
17
|
+
policyLabel?: string;
|
|
18
|
+
acceptLabel?: string;
|
|
19
|
+
declineLabel?: string;
|
|
20
|
+
class?: HTMLAttributes['class'];
|
|
21
|
+
}>(), {
|
|
22
|
+
storageKey: 'cookieConsent',
|
|
23
|
+
message: undefined,
|
|
24
|
+
policyTo: undefined,
|
|
25
|
+
policyLabel: undefined,
|
|
26
|
+
acceptLabel: undefined,
|
|
27
|
+
declineLabel: undefined,
|
|
28
|
+
class: undefined
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Emits
|
|
32
|
+
const emit = defineEmits<{
|
|
33
|
+
accept: [];
|
|
34
|
+
decline: [];
|
|
35
|
+
}>();
|
|
36
|
+
|
|
37
|
+
const { t } = useI18n();
|
|
38
|
+
const { consent, accept, decline } = useCookieConsent(props.storageKey);
|
|
39
|
+
const hasMounted = ref(false);
|
|
40
|
+
|
|
41
|
+
// Shown in the browser only, until the visitor chooses (the stored choice is not known on the server)
|
|
42
|
+
const isVisible = computed(() => hasMounted.value && consent.value === null);
|
|
43
|
+
|
|
44
|
+
// Texts, with translated defaults
|
|
45
|
+
const resolvedMessage = computed(() => props.message || t('uiVintage.cookieConsent.message'));
|
|
46
|
+
const resolvedPolicyLabel = computed(() => props.policyLabel || t('uiVintage.cookieConsent.policy'));
|
|
47
|
+
const resolvedAcceptLabel = computed(() => props.acceptLabel || t('uiVintage.cookieConsent.accept'));
|
|
48
|
+
const resolvedDeclineLabel = computed(() => props.declineLabel || t('uiVintage.cookieConsent.decline'));
|
|
49
|
+
|
|
50
|
+
// Save the choice and notify
|
|
51
|
+
const handleAccept = () => {
|
|
52
|
+
accept();
|
|
53
|
+
emit('accept');
|
|
54
|
+
};
|
|
55
|
+
const handleDecline = () => {
|
|
56
|
+
decline();
|
|
57
|
+
emit('decline');
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Wait for the browser before showing the banner
|
|
61
|
+
onMounted(() => {
|
|
62
|
+
hasMounted.value = true;
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<template>
|
|
67
|
+
<!-- Rendered in the body: a transformed or filtered ancestor (page transitions, reveal animations) would otherwise pin the fixed banner to itself instead of the viewport -->
|
|
68
|
+
<Teleport to="body">
|
|
69
|
+
<div v-if="isVisible" v-bind="$attrs" data-slot="cookie-consent" role="region" :aria-label="t('uiVintage.cookieConsent.region')" :class="cn('fixed inset-x-4 bottom-4 z-50 sm:left-auto sm:right-4 sm:max-w-md', props.class)">
|
|
70
|
+
<Card class="gap-3! p-4 shadow-elevated-sm">
|
|
71
|
+
<p class="text-sm text-foreground">
|
|
72
|
+
{{ resolvedMessage }}
|
|
73
|
+
<NuxtLinkLocale v-if="props.policyTo" :to="props.policyTo" class="font-bold underline underline-offset-2">{{ resolvedPolicyLabel }}</NuxtLinkLocale>
|
|
74
|
+
</p>
|
|
75
|
+
<div class="flex flex-wrap justify-end gap-2">
|
|
76
|
+
<Button variant="secondary" size="sm" @click="handleDecline">{{ resolvedDeclineLabel }}</Button>
|
|
77
|
+
<Button variant="primary" size="sm" @click="handleAccept">{{ resolvedAcceptLabel }}</Button>
|
|
78
|
+
</div>
|
|
79
|
+
</Card>
|
|
80
|
+
</div>
|
|
81
|
+
</Teleport>
|
|
82
|
+
</template>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { ref, type Ref } from 'vue';
|
|
2
|
+
|
|
3
|
+
// The visitor's choice: 'granted', 'denied' or null (not asked yet)
|
|
4
|
+
export type CookieConsentValue = 'granted' | 'denied' | null;
|
|
5
|
+
|
|
6
|
+
// One shared state per storage key, so the banner and the code loading the scripts stay in sync (browser only)
|
|
7
|
+
const consentStates = new Map<string, Ref<CookieConsentValue>>();
|
|
8
|
+
|
|
9
|
+
// Read the stored choice (storage can be unavailable, e.g. blocked in private windows)
|
|
10
|
+
const readStoredConsent = (storageKey: string): CookieConsentValue => {
|
|
11
|
+
try {
|
|
12
|
+
const value = localStorage.getItem(storageKey);
|
|
13
|
+
return value === 'granted' || value === 'denied' ? value : null;
|
|
14
|
+
} catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Cookie consent state: gate optional scripts (analytics, ads) on `consent.value === 'granted'` and call `reset()` to ask again
|
|
20
|
+
export const useCookieConsent = (storageKey = 'cookieConsent') => {
|
|
21
|
+
// On the server there is no stored choice (and no state must be shared between requests)
|
|
22
|
+
if (typeof window === 'undefined') {
|
|
23
|
+
const consent = ref<CookieConsentValue>(null);
|
|
24
|
+
const noop = () => {};
|
|
25
|
+
return { consent, accept: noop, decline: noop, reset: noop };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Shared state for this key
|
|
29
|
+
let consent = consentStates.get(storageKey);
|
|
30
|
+
if (!consent) {
|
|
31
|
+
consent = ref(readStoredConsent(storageKey));
|
|
32
|
+
consentStates.set(storageKey, consent);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Save a choice (null removes it, so the banner asks again)
|
|
36
|
+
const state = consent;
|
|
37
|
+
const setConsent = (value: CookieConsentValue) => {
|
|
38
|
+
state.value = value;
|
|
39
|
+
try {
|
|
40
|
+
if (value) {
|
|
41
|
+
localStorage.setItem(storageKey, value);
|
|
42
|
+
} else {
|
|
43
|
+
localStorage.removeItem(storageKey);
|
|
44
|
+
}
|
|
45
|
+
} catch { }
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
// Return the state and the actions
|
|
49
|
+
return {
|
|
50
|
+
consent: state,
|
|
51
|
+
accept: () => setConsent('granted'),
|
|
52
|
+
decline: () => setConsent('denied'),
|
|
53
|
+
reset: () => setConsent(null)
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { HTMLAttributes } from 'vue';
|
|
3
|
-
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
|
3
|
+
import { computed, getCurrentInstance, onBeforeMount, onBeforeUnmount, onMounted, ref, watch } from 'vue';
|
|
4
4
|
import { cn } from '../../../lib/utils';
|
|
5
5
|
|
|
6
6
|
// Props
|
|
@@ -22,8 +22,12 @@ const props = withDefaults(defineProps<{
|
|
|
22
22
|
animateOnMount: true
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// The server always renders the final value (search engines, link previews and the first paint never see a 0), the count-up only runs for components created in the browser
|
|
26
|
+
const isServer = typeof window === 'undefined';
|
|
27
|
+
const displayValue = ref(props.animateOnMount && !isServer ? 0 : props.value);
|
|
26
28
|
const direction = ref<'up' | 'down' | null>(null);
|
|
29
|
+
const instance = getCurrentInstance();
|
|
30
|
+
let isHydrated = false;
|
|
27
31
|
let frame: number | null = null;
|
|
28
32
|
|
|
29
33
|
// Format the displayed value
|
|
@@ -34,6 +38,9 @@ const formatter = computed(() => {
|
|
|
34
38
|
});
|
|
35
39
|
const formattedValue = computed(() => `${props.prefix}${formatter.value.format(displayValue.value)}${props.suffix}`);
|
|
36
40
|
|
|
41
|
+
// Final value announced to screen readers from visually hidden text (the animated digits are hidden from them, and aria-label is not allowed on a span without a role)
|
|
42
|
+
const accessibleValue = computed(() => `${props.prefix}${formatter.value.format(props.value)}${props.suffix}`);
|
|
43
|
+
|
|
37
44
|
// Decelerating curve so the count settles gently on the final value
|
|
38
45
|
const easeOutExpo = (progress: number) => progress === 1 ? 1 : 1 - Math.pow(2, -10 * progress);
|
|
39
46
|
|
|
@@ -70,9 +77,15 @@ const animateTo = (target: number) => {
|
|
|
70
77
|
// Re-animate whenever the value changes
|
|
71
78
|
watch(() => props.value, value => animateTo(value));
|
|
72
79
|
|
|
73
|
-
//
|
|
80
|
+
// When hydrating server HTML (the element already exists before the first render), keep the final value the server rendered, so there is no mismatch and no flash to 0
|
|
81
|
+
onBeforeMount(() => {
|
|
82
|
+
isHydrated = !!instance?.vnode.el;
|
|
83
|
+
if (isHydrated) displayValue.value = props.value;
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
// Count up on mount (only for components created in the browser, server-rendered ones already show the final value)
|
|
74
87
|
onMounted(() => {
|
|
75
|
-
if (props.animateOnMount) animateTo(props.value);
|
|
88
|
+
if (props.animateOnMount && !isHydrated) animateTo(props.value);
|
|
76
89
|
});
|
|
77
90
|
|
|
78
91
|
// Stop any pending frame
|
|
@@ -82,7 +95,8 @@ onBeforeUnmount(() => {
|
|
|
82
95
|
</script>
|
|
83
96
|
|
|
84
97
|
<template>
|
|
85
|
-
<span data-slot="animated-number" :data-direction="direction ?? undefined" :
|
|
98
|
+
<span data-slot="animated-number" :data-direction="direction ?? undefined" :class="cn('inline-block tabular-nums', props.class)">
|
|
86
99
|
<span aria-hidden="true">{{ formattedValue }}</span>
|
|
100
|
+
<span class="sr-only">{{ accessibleValue }}</span>
|
|
87
101
|
</span>
|
|
88
102
|
</template>
|
package/src/i18n/de.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "Benachrichtigungen"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Cookie-Einwilligung",
|
|
123
|
+
"message": "Wir verwenden optionale Cookies, um zu verstehen, wie die Website genutzt wird. Sie werden nur gesetzt, wenn du zustimmst.",
|
|
124
|
+
"policy": "Cookie-Richtlinie",
|
|
125
|
+
"accept": "Akzeptieren",
|
|
126
|
+
"decline": "Ablehnen"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "Alle Zeilen auswählen",
|
|
123
130
|
"selectRow": "Zeile auswählen"
|
package/src/i18n/en.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "Notifications"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Cookie consent",
|
|
123
|
+
"message": "We use optional cookies to understand how the site is used. They are only set if you accept.",
|
|
124
|
+
"policy": "Cookie policy",
|
|
125
|
+
"accept": "Accept",
|
|
126
|
+
"decline": "Decline"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "Select all rows",
|
|
123
130
|
"selectRow": "Select row"
|
package/src/i18n/es.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "Notificaciones"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Consentimiento de cookies",
|
|
123
|
+
"message": "Usamos cookies opcionales para entender cómo se usa el sitio. Solo se instalan si aceptas.",
|
|
124
|
+
"policy": "Política de cookies",
|
|
125
|
+
"accept": "Aceptar",
|
|
126
|
+
"decline": "Rechazar"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "Seleccionar todas las filas",
|
|
123
130
|
"selectRow": "Seleccionar fila"
|
package/src/i18n/fr.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "Notifications"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Consentement aux cookies",
|
|
123
|
+
"message": "Nous utilisons des cookies facultatifs pour comprendre comment le site est utilisé. Ils ne sont déposés que si vous acceptez.",
|
|
124
|
+
"policy": "Politique relative aux cookies",
|
|
125
|
+
"accept": "Accepter",
|
|
126
|
+
"decline": "Refuser"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "Sélectionner toutes les lignes",
|
|
123
130
|
"selectRow": "Sélectionner la ligne"
|
package/src/i18n/it.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "Notifiche"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Consenso ai cookie",
|
|
123
|
+
"message": "Usiamo cookie facoltativi per capire come viene usato il sito. Vengono impostati solo se accetti.",
|
|
124
|
+
"policy": "Politica sui cookie",
|
|
125
|
+
"accept": "Accetta",
|
|
126
|
+
"decline": "Rifiuta"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "Seleziona tutte le righe",
|
|
123
130
|
"selectRow": "Seleziona riga"
|
package/src/i18n/ja.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "通知"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Cookieの同意",
|
|
123
|
+
"message": "サイトの利用状況を把握するため、任意のCookieを使用しています。同意した場合にのみ設定されます。",
|
|
124
|
+
"policy": "Cookieポリシー",
|
|
125
|
+
"accept": "同意する",
|
|
126
|
+
"decline": "拒否する"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "すべての行を選択",
|
|
123
130
|
"selectRow": "行を選択"
|
package/src/i18n/pt.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "Notificações"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Consentimento de cookies",
|
|
123
|
+
"message": "Usamos cookies opcionais para entender como o site é usado. Eles só são definidos se você aceitar.",
|
|
124
|
+
"policy": "Política de cookies",
|
|
125
|
+
"accept": "Aceitar",
|
|
126
|
+
"decline": "Recusar"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "Selecionar todas as linhas",
|
|
123
130
|
"selectRow": "Selecionar linha"
|
package/src/i18n/ru.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "Уведомления"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Согласие на cookie",
|
|
123
|
+
"message": "Мы используем необязательные файлы cookie, чтобы понимать, как используется сайт. Они устанавливаются только с вашего согласия.",
|
|
124
|
+
"policy": "Политика cookie",
|
|
125
|
+
"accept": "Принять",
|
|
126
|
+
"decline": "Отклонить"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "Выбрать все строки",
|
|
123
130
|
"selectRow": "Выбрать строку"
|
package/src/i18n/zh.json
CHANGED
|
@@ -118,6 +118,13 @@
|
|
|
118
118
|
"toast": {
|
|
119
119
|
"region": "通知"
|
|
120
120
|
},
|
|
121
|
+
"cookieConsent": {
|
|
122
|
+
"region": "Cookie 同意",
|
|
123
|
+
"message": "我们使用可选的 Cookie 来了解网站的使用情况。只有在您同意后才会设置。",
|
|
124
|
+
"policy": "Cookie 政策",
|
|
125
|
+
"accept": "接受",
|
|
126
|
+
"decline": "拒绝"
|
|
127
|
+
},
|
|
121
128
|
"dataTable": {
|
|
122
129
|
"selectAll": "全选所有行",
|
|
123
130
|
"selectRow": "选择行"
|