@riducms/plugin-seo 0.16.1 → 0.17.0

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 (37) hide show
  1. package/dist/generation-controller.svelte.d.ts +7 -0
  2. package/dist/generation-controller.svelte.js +68 -0
  3. package/dist/generation-snapshot.d.ts +3 -0
  4. package/dist/generation-snapshot.js +11 -0
  5. package/dist/index.d.ts +59 -0
  6. package/dist/index.js +48 -0
  7. package/dist/length-indicator.d.ts +8 -0
  8. package/dist/length-indicator.js +24 -0
  9. package/{src → dist}/length-indicator.svelte +2 -2
  10. package/dist/length-indicator.svelte.d.ts +11 -0
  11. package/dist/messages.d.ts +33 -0
  12. package/dist/messages.js +104 -0
  13. package/{src → dist}/meta-description-field.svelte +4 -4
  14. package/dist/meta-description-field.svelte.d.ts +6 -0
  15. package/{src → dist}/meta-image-field.svelte +5 -5
  16. package/dist/meta-image-field.svelte.d.ts +7 -0
  17. package/{src → dist}/meta-title-field.svelte +4 -4
  18. package/dist/meta-title-field.svelte.d.ts +6 -0
  19. package/{src → dist}/overview-field.svelte +2 -2
  20. package/dist/overview-field.svelte.d.ts +6 -0
  21. package/{src → dist}/preview-field.svelte +3 -3
  22. package/dist/preview-field.svelte.d.ts +6 -0
  23. package/dist/seo-config.d.ts +27 -0
  24. package/dist/seo-config.js +74 -0
  25. package/dist/seo.css +308 -0
  26. package/dist/~icons/lucide/image.svelte +2 -0
  27. package/dist/~icons/lucide/pencil.svelte +2 -0
  28. package/dist/~icons/lucide/x.svelte +2 -0
  29. package/package.json +32 -13
  30. package/src/generation-controller.svelte.ts +0 -84
  31. package/src/generation-snapshot.ts +0 -17
  32. package/src/index.ts +0 -59
  33. package/src/length-indicator.ts +0 -32
  34. package/src/messages.ts +0 -113
  35. package/src/seo-config.ts +0 -96
  36. package/src/vite-env.d.ts +0 -7
  37. /package/{src → dist}/seo.scss +0 -0
package/dist/seo.css ADDED
@@ -0,0 +1,308 @@
1
+ @layer ridu, ridu-plugins, app;
2
+ @layer ridu.reset, ridu.theme, ridu.base, ridu.components, ridu.utilities;
3
+ @layer ridu.components {
4
+ .ridu-seo-overview,
5
+ .ridu-seo-field,
6
+ .ridu-seo-preview {
7
+ min-width: 0;
8
+ }
9
+ .ridu-seo-field,
10
+ .ridu-seo-field .ridu-field-control {
11
+ gap: 0;
12
+ }
13
+ .ridu-seo-overview {
14
+ color: var(--foreground);
15
+ font-size: var(--font-size-body);
16
+ line-height: var(--line-height-body);
17
+ }
18
+ .ridu-seo-overview p {
19
+ margin: 0;
20
+ }
21
+ .ridu-seo-heading-separator {
22
+ color: var(--ink-muted);
23
+ }
24
+ .ridu-seo-generate.ridu-button {
25
+ block-size: auto;
26
+ border: 0;
27
+ padding: 0;
28
+ color: currentColor;
29
+ font-size: inherit;
30
+ line-height: inherit;
31
+ }
32
+ .ridu-seo-guidance {
33
+ margin: 0 0 5px;
34
+ color: var(--ink-muted);
35
+ font-size: var(--font-size-body);
36
+ line-height: var(--line-height-body);
37
+ }
38
+ .ridu-seo-guidance-link {
39
+ color: inherit;
40
+ text-decoration: underline;
41
+ text-underline-offset: 2px;
42
+ }
43
+ .ridu-seo-guidance-link:focus-visible {
44
+ outline: var(--focus-outline);
45
+ outline-offset: var(--focus-outline-offset);
46
+ }
47
+ .ridu-seo-description[data-empty=false] {
48
+ min-height: 0;
49
+ }
50
+ .ridu-seo-error {
51
+ margin: 0;
52
+ color: var(--destructive);
53
+ font-size: var(--font-size-body);
54
+ line-height: var(--line-height-body);
55
+ }
56
+ .ridu-seo-length {
57
+ margin-block-start: 10px;
58
+ display: grid;
59
+ grid-template-columns: auto auto minmax(32px, 1fr);
60
+ align-items: center;
61
+ gap: 10px;
62
+ min-width: 0;
63
+ }
64
+ .ridu-seo-pill {
65
+ display: inline-flex;
66
+ align-items: center;
67
+ flex-shrink: 0;
68
+ inline-size: max-content;
69
+ border-radius: 2px;
70
+ padding: 4px 6px;
71
+ font-size: 11px;
72
+ font-weight: 400;
73
+ line-height: 1;
74
+ white-space: nowrap;
75
+ }
76
+ .ridu-seo-pill[data-tone=danger],
77
+ .ridu-seo-pill[data-status=missing],
78
+ .ridu-seo-pill[data-status=tooLong] {
79
+ background: var(--seo-status-danger);
80
+ color: var(--seo-status-danger-foreground);
81
+ }
82
+ .ridu-seo-pill[data-status=tooShort] {
83
+ background: var(--seo-status-short);
84
+ color: var(--seo-status-short-foreground);
85
+ }
86
+ .ridu-seo-pill[data-tone=warning],
87
+ .ridu-seo-pill[data-status=almostThere] {
88
+ background: var(--seo-status-warning);
89
+ color: var(--seo-status-warning-foreground);
90
+ }
91
+ .ridu-seo-pill[data-tone=success],
92
+ .ridu-seo-pill[data-status=good] {
93
+ background: var(--seo-status-success);
94
+ color: var(--seo-status-success-foreground);
95
+ }
96
+ .ridu-seo-length-copy {
97
+ color: var(--foreground);
98
+ font-size: 11px;
99
+ line-height: 1;
100
+ white-space: nowrap;
101
+ }
102
+ .ridu-seo-progress {
103
+ position: relative;
104
+ height: 2px;
105
+ min-width: 32px;
106
+ overflow: hidden;
107
+ background: var(--seo-status-track);
108
+ }
109
+ .ridu-seo-progress-value {
110
+ display: block;
111
+ width: 100%;
112
+ height: 100%;
113
+ transform-origin: left center;
114
+ transition: transform 150ms ease;
115
+ }
116
+ .ridu-seo-length:dir(rtl) .ridu-seo-progress-value {
117
+ transform-origin: right center;
118
+ }
119
+ .ridu-seo-progress-value[data-status=missing],
120
+ .ridu-seo-progress-value[data-status=tooLong] {
121
+ background: var(--seo-status-danger);
122
+ }
123
+ .ridu-seo-progress-value[data-status=tooShort] {
124
+ background: var(--seo-status-short);
125
+ }
126
+ .ridu-seo-progress-value[data-status=almostThere] {
127
+ background: var(--seo-status-warning);
128
+ }
129
+ .ridu-seo-progress-value[data-status=good] {
130
+ background: var(--seo-status-success);
131
+ }
132
+ .ridu-seo-image-intake {
133
+ display: flex;
134
+ align-items: center;
135
+ flex-wrap: wrap;
136
+ gap: 10px;
137
+ min-height: 60px;
138
+ border: 1px dashed var(--control-border);
139
+ border-radius: var(--control-radius);
140
+ padding: 15px;
141
+ color: var(--foreground-muted);
142
+ }
143
+ .ridu-seo-image-intake[data-invalid=true] {
144
+ border-color: var(--control-invalid-border);
145
+ background: var(--control-invalid-surface);
146
+ }
147
+ .ridu-seo-image-intake[data-dragging=true] {
148
+ border-color: var(--foreground);
149
+ background: var(--control-surface);
150
+ }
151
+ .ridu-seo-image-intake-copy {
152
+ margin-inline-start: auto;
153
+ font-size: var(--font-size-body);
154
+ line-height: var(--line-height-body);
155
+ }
156
+ .ridu-seo-image-selection {
157
+ display: flex;
158
+ align-items: center;
159
+ gap: 10px;
160
+ box-sizing: border-box;
161
+ height: 60px;
162
+ min-width: 0;
163
+ border: 1px solid var(--control-border);
164
+ border-radius: var(--control-radius);
165
+ padding: 10px;
166
+ background: var(--control-surface);
167
+ }
168
+ .ridu-seo-image-selection[aria-invalid=true] {
169
+ border-color: var(--control-invalid-border);
170
+ background: var(--control-invalid-surface);
171
+ }
172
+ .ridu-seo-image-content {
173
+ display: flex;
174
+ align-items: center;
175
+ flex: 1;
176
+ gap: 10px;
177
+ min-width: 0;
178
+ }
179
+ .ridu-seo-image-thumbnail {
180
+ display: grid;
181
+ place-items: center;
182
+ flex-shrink: 0;
183
+ width: 40px;
184
+ height: 40px;
185
+ overflow: hidden;
186
+ border-radius: var(--control-radius);
187
+ background: var(--background);
188
+ color: var(--ink-faint);
189
+ }
190
+ .ridu-seo-image-thumbnail img {
191
+ width: 100%;
192
+ height: 100%;
193
+ object-fit: cover;
194
+ }
195
+ .ridu-seo-image-thumbnail svg {
196
+ width: 14px;
197
+ height: 14px;
198
+ }
199
+ .ridu-seo-image-details {
200
+ display: flex;
201
+ flex-direction: column;
202
+ min-width: 0;
203
+ flex: 1;
204
+ }
205
+ .ridu-seo-image-name,
206
+ .ridu-seo-image-metadata {
207
+ display: block;
208
+ overflow: hidden;
209
+ text-overflow: ellipsis;
210
+ white-space: nowrap;
211
+ }
212
+ .ridu-seo-image-name {
213
+ color: var(--ink-strong);
214
+ font-size: var(--font-size-body);
215
+ line-height: var(--line-height-body);
216
+ text-decoration: none;
217
+ }
218
+ .ridu-seo-image-name:focus-visible {
219
+ outline: var(--focus-outline);
220
+ outline-offset: var(--focus-outline-offset);
221
+ }
222
+ .ridu-seo-image-metadata {
223
+ color: var(--ink-muted);
224
+ font-size: var(--font-size-body);
225
+ line-height: var(--line-height-body);
226
+ }
227
+ .ridu-seo-image-actions {
228
+ display: flex;
229
+ flex-shrink: 0;
230
+ }
231
+ .ridu-seo-image-actions .ridu-button {
232
+ border: 0;
233
+ }
234
+ .ridu-seo-image-status {
235
+ display: flex;
236
+ align-items: center;
237
+ margin-block-start: 10px;
238
+ }
239
+ .ridu-seo-preview {
240
+ display: grid;
241
+ gap: 0;
242
+ }
243
+ .ridu-seo-preview-heading,
244
+ .ridu-seo-preview-description,
245
+ .ridu-seo-preview-url,
246
+ .ridu-seo-preview-title,
247
+ .ridu-seo-preview-copy {
248
+ margin: 0;
249
+ }
250
+ .ridu-seo-preview-heading {
251
+ color: var(--ink-label);
252
+ font-size: var(--font-size-body);
253
+ font-weight: 400;
254
+ line-height: var(--line-height-body);
255
+ }
256
+ .ridu-seo-preview-description {
257
+ margin-block-end: 5px;
258
+ color: var(--ink-muted);
259
+ font-size: var(--font-size-body);
260
+ line-height: var(--line-height-body);
261
+ }
262
+ .ridu-seo-preview-card {
263
+ box-sizing: border-box;
264
+ width: 100%;
265
+ max-width: 600px;
266
+ overflow: hidden;
267
+ border-radius: 5px;
268
+ padding: 20px;
269
+ background: var(--control-surface);
270
+ box-shadow: var(--seo-preview-shadow);
271
+ pointer-events: none;
272
+ }
273
+ .ridu-seo-preview-url,
274
+ .ridu-seo-preview-title,
275
+ .ridu-seo-preview-copy {
276
+ overflow-wrap: anywhere;
277
+ color: var(--foreground);
278
+ }
279
+ .ridu-seo-preview-url {
280
+ font-size: var(--font-size-body);
281
+ line-height: var(--line-height-body);
282
+ }
283
+ .ridu-seo-preview-title {
284
+ font-size: 16px;
285
+ font-weight: 500;
286
+ line-height: 20px;
287
+ }
288
+ .ridu-seo-preview-copy {
289
+ font-size: var(--font-size-body);
290
+ line-height: var(--line-height-body);
291
+ }
292
+ @media (max-width: 30rem) {
293
+ .ridu-seo-length {
294
+ grid-template-columns: auto minmax(0, 1fr);
295
+ }
296
+ .ridu-seo-progress {
297
+ grid-column: 1/-1;
298
+ }
299
+ .ridu-seo-image-intake-copy {
300
+ display: none;
301
+ }
302
+ }
303
+ @media (prefers-reduced-motion: reduce) {
304
+ .ridu-seo-progress-value {
305
+ transition: none;
306
+ }
307
+ }
308
+ }
@@ -0,0 +1,2 @@
1
+ <!-- Lucide by Lucide Contributors, ISC (https://github.com/lucide-icons/lucide/blob/main/LICENSE) -->
2
+ <script>const{...p}=$props()</script><svg viewBox="0 0 24 24" width="1.2em" height="1.2em" {...p}><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15l-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></g></svg>
@@ -0,0 +1,2 @@
1
+ <!-- Lucide by Lucide Contributors, ISC (https://github.com/lucide-icons/lucide/blob/main/LICENSE) -->
2
+ <script>const{...p}=$props()</script><svg viewBox="0 0 24 24" width="1.2em" height="1.2em" {...p}><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497zM15 5l4 4"/></svg>
@@ -0,0 +1,2 @@
1
+ <!-- Lucide by Lucide Contributors, ISC (https://github.com/lucide-icons/lucide/blob/main/LICENSE) -->
2
+ <script>const{...p}=$props()</script><svg viewBox="0 0 24 24" width="1.2em" height="1.2em" {...p}><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18 6L6 18M6 6l12 12"/></svg>
package/package.json CHANGED
@@ -3,25 +3,34 @@
3
3
  "url": "https://github.com/riducms/ridu/issues"
4
4
  },
5
5
  "dependencies": {
6
- "@riducms/plugin": "0.16.1",
7
- "@riducms/protocol": "0.16.1",
8
- "@riducms/ui": "0.16.1",
9
- "svelte": "^5.56.8"
6
+ "@riducms/plugin": "0.17.0",
7
+ "@riducms/protocol": "0.17.0",
8
+ "@riducms/ui": "0.17.0"
10
9
  },
11
10
  "description": "Search metadata authoring for Ridu's official SEO plugin.",
12
- "devDependencies": {
13
- "@riducms/build": "0.16.1"
14
- },
15
11
  "exports": {
16
- ".": "./src/index.ts"
12
+ ".": {
13
+ "default": "./dist/index.js",
14
+ "svelte": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ }
17
17
  },
18
18
  "files": [
19
- "src",
19
+ "dist",
20
+ "!dist/**/*.test.*",
21
+ "!dist/**/*.spec.*",
20
22
  "LICENSE"
21
23
  ],
22
24
  "homepage": "https://riducms.com",
25
+ "imports": {
26
+ "#lib": "./src/lib/index.js",
27
+ "#lib/*": "./src/lib/*"
28
+ },
23
29
  "license": "MIT",
24
30
  "name": "@riducms/plugin-seo",
31
+ "peerDependencies": {
32
+ "svelte": "^5.56.8"
33
+ },
25
34
  "publishConfig": {
26
35
  "access": "public",
27
36
  "provenance": true
@@ -32,10 +41,20 @@
32
41
  "url": "git+https://github.com/riducms/ridu.git"
33
42
  },
34
43
  "scripts": {
35
- "build": "vite build",
36
- "check": "svelte-check --tsconfig ./tsconfig.json",
37
- "test": "bun test"
44
+ "build": "bun run package",
45
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
46
+ "dev": "svelte-kit sync && bun run --parallel dev:package dev:finish",
47
+ "dev:finish": "bun ../../scripts/finish-svelte-package.ts --watch",
48
+ "dev:package": "svelte-package --watch",
49
+ "package": "svelte-kit sync && svelte-package && bun ../../scripts/finish-svelte-package.ts && publint",
50
+ "test": "svelte-kit sync && bun test"
38
51
  },
52
+ "sideEffects": [
53
+ "**/*.css",
54
+ "**/*.scss"
55
+ ],
56
+ "svelte": "./dist/index.js",
39
57
  "type": "module",
40
- "version": "0.16.1"
58
+ "types": "./dist/index.d.ts",
59
+ "version": "0.17.0"
41
60
  }
@@ -1,84 +0,0 @@
1
- import type { FieldAuthoringHost, FieldDocumentForm } from "@riducms/plugin";
2
-
3
- import { generationScopeToken, generationSnapshotToken } from "@plugin-seo/generation-snapshot";
4
-
5
- interface GenerationResponse {
6
- result: string;
7
- }
8
-
9
- export class GenerationController {
10
- status = $state<"idle" | "pending" | "error">("idle");
11
- #generation = 0;
12
- #request: AbortController | undefined;
13
-
14
- async run(
15
- authoring: FieldAuthoringHost | undefined,
16
- form: FieldDocumentForm,
17
- path: string
18
- ): Promise<string | undefined> {
19
- const requestPlugin = authoring?.requestPlugin;
20
- const snapshot = form.snapshot;
21
- const resource = form.resource;
22
- if (requestPlugin === undefined || snapshot === undefined || resource === undefined) {
23
- this.status = "error";
24
- return undefined;
25
- }
26
- this.#request?.abort();
27
- const request = new AbortController();
28
- this.#request = request;
29
- const generation = ++this.#generation;
30
- this.status = "pending";
31
- const document = snapshot.call(form);
32
- const documentRevision = generationSnapshotToken(document);
33
- const scope = generationScopeToken(resource, form.contentLocale);
34
- try {
35
- const response = await requestPlugin<unknown>(
36
- path,
37
- {
38
- ...(resource.global
39
- ? { global: resource.collection }
40
- : { collection: resource.collection }),
41
- id: resource.id,
42
- locale: form.contentLocale,
43
- document,
44
- },
45
- request.signal
46
- );
47
- if (
48
- generation !== this.#generation ||
49
- request.signal.aborted ||
50
- generationSnapshotToken(snapshot.call(form)) !== documentRevision ||
51
- generationScopeToken(form.resource, form.contentLocale) !== scope
52
- ) {
53
- if (generation === this.#generation) this.status = "idle";
54
- return undefined;
55
- }
56
- if (!isGenerationResponse(response))
57
- throw new Error("SEO generation returned an invalid response");
58
- this.status = "idle";
59
- return response.result;
60
- } catch {
61
- if (generation !== this.#generation || request.signal.aborted) return undefined;
62
- this.status = "error";
63
- return undefined;
64
- } finally {
65
- if (this.#request === request) this.#request = undefined;
66
- }
67
- }
68
-
69
- cancel() {
70
- this.#generation += 1;
71
- this.#request?.abort();
72
- this.#request = undefined;
73
- if (this.status === "pending") this.status = "idle";
74
- }
75
- }
76
-
77
- function isGenerationResponse(value: unknown): value is GenerationResponse {
78
- return (
79
- typeof value === "object" &&
80
- value !== null &&
81
- "result" in value &&
82
- typeof value.result === "string"
83
- );
84
- }
@@ -1,17 +0,0 @@
1
- import type { FieldFormResource } from "@riducms/plugin";
2
-
3
- export function generationSnapshotToken(document: Readonly<Record<string, unknown>>): string {
4
- return JSON.stringify(document);
5
- }
6
-
7
- export function generationScopeToken(
8
- resource: FieldFormResource | undefined,
9
- locale: string | undefined
10
- ): string {
11
- return JSON.stringify({
12
- collection: resource?.collection ?? "",
13
- global: resource?.global === true,
14
- id: resource?.id ?? "",
15
- locale: locale ?? "",
16
- });
17
- }
package/src/index.ts DELETED
@@ -1,59 +0,0 @@
1
- import { defineAdminPlugin, defineFieldComponent } from "@riducms/plugin/authoring/v1";
2
- import {
3
- decodeString,
4
- decodeUI,
5
- decodeLengthConfig,
6
- decodeOverviewConfig,
7
- decodeImageConfig,
8
- decodePreviewConfig,
9
- } from "@plugin-seo/seo-config";
10
-
11
- import { seoMessages } from "@plugin-seo/messages";
12
-
13
- import MetaDescriptionField from "@plugin-seo/meta-description-field.svelte";
14
- import MetaImageField from "@plugin-seo/meta-image-field.svelte";
15
- import MetaTitleField from "@plugin-seo/meta-title-field.svelte";
16
- import OverviewField from "@plugin-seo/overview-field.svelte";
17
- import PreviewField from "@plugin-seo/preview-field.svelte";
18
-
19
- export const seoAdminPlugin = defineAdminPlugin({
20
- key: "seo",
21
- pairingVersion: 1,
22
- fieldEditors: {
23
- overview: defineFieldComponent({
24
- type: "ui",
25
- component: OverviewField,
26
- decodeValue: decodeUI,
27
- decodeConfig: decodeOverviewConfig,
28
- }),
29
- title: defineFieldComponent({
30
- type: "text",
31
- component: MetaTitleField,
32
- decodeValue: decodeString,
33
- decodeConfig: (raw: unknown) => decodeLengthConfig(raw, "text"),
34
- }),
35
- description: defineFieldComponent({
36
- type: "textarea",
37
- component: MetaDescriptionField,
38
- decodeValue: decodeString,
39
- decodeConfig: (raw: unknown) => decodeLengthConfig(raw, "textarea"),
40
- }),
41
- image: defineFieldComponent({
42
- type: "upload",
43
- component: MetaImageField,
44
- decodeValue: decodeString,
45
- decodeConfig: decodeImageConfig,
46
- }),
47
- preview: defineFieldComponent({
48
- type: "ui",
49
- component: PreviewField,
50
- decodeValue: decodeUI,
51
- decodeConfig: decodePreviewConfig,
52
- }),
53
- },
54
- messages: seoMessages,
55
- });
56
-
57
- export { lengthState, type LengthState, type LengthStatus } from "@plugin-seo/length-indicator";
58
- export { generationScopeToken, generationSnapshotToken } from "@plugin-seo/generation-snapshot";
59
- export { seoMessages } from "@plugin-seo/messages";
@@ -1,32 +0,0 @@
1
- export type LengthStatus = "missing" | "tooShort" | "almostThere" | "good" | "tooLong";
2
-
3
- export interface LengthState {
4
- status: LengthStatus;
5
- length: number;
6
- progress: number;
7
- remaining: number;
8
- }
9
-
10
- export function lengthState(text: string, minLength: number, maxLength: number): LengthState {
11
- const length = text.length;
12
- if (length === 0) return { status: "missing", length, progress: 0, remaining: minLength };
13
- if (length < minLength) {
14
- const progress = Math.min(1, length / minLength);
15
- return {
16
- status: progress > 0.9 ? "almostThere" : "tooShort",
17
- length,
18
- progress,
19
- remaining: minLength - length,
20
- };
21
- }
22
- if (length <= maxLength) {
23
- const range = Math.max(1, maxLength - minLength);
24
- return {
25
- status: "good",
26
- length,
27
- progress: Math.min(1, (length - minLength) / range),
28
- remaining: maxLength - length,
29
- };
30
- }
31
- return { status: "tooLong", length, progress: 1, remaining: length - maxLength };
32
- }
package/src/messages.ts DELETED
@@ -1,113 +0,0 @@
1
- import { defineAdminMessages } from "@riducms/plugin";
2
-
3
- export const seoMessages = defineAdminMessages({
4
- fallback: {
5
- almostThere: "Almost there",
6
- autoGenerate: "Auto-generate",
7
- bestPractices: "best practices",
8
- cancelled: "Generation was cancelled.",
9
- characterCount: "{current}/{minLength}-{maxLength} chars",
10
- charactersLeft: ", {characters} left over",
11
- charactersToGo: ", {characters} to go",
12
- charactersTooMany: ", {characters} too many",
13
- checksPassing: "{current}/{max} checks are passing",
14
- chooseExistingImage: "Choose existing",
15
- createNewImage: "Create new",
16
- generationFailed: "Could not generate this value. Try again.",
17
- good: "Good",
18
- image: "Image",
19
- imageAutoGenerationTip: "Generate an image from the current document, or choose one manually.",
20
- imageSourceTip: "or drag and drop a file.",
21
- imageUnavailable: "Referenced image is unavailable.",
22
- inspectImage: "Inspect image",
23
- lengthTipDescription:
24
- "This should be between {minLength} and {maxLength} characters. For help in writing quality meta descriptions, see ",
25
- lengthTipTitle:
26
- "This should be between {minLength} and {maxLength} characters. For help in writing quality meta titles, see ",
27
- missing: "Missing",
28
- noImage: "No image",
29
- or: "or",
30
- preview: "Preview",
31
- previewDescription: "Exact result listings may vary based on content and search relevancy.",
32
- removeImage: "Remove image",
33
- selectImage: "Select image",
34
- tooLong: "Too long",
35
- tooShort: "Too short",
36
- title: "Title",
37
- description: "Description",
38
- },
39
- translations: {
40
- fr: {
41
- almostThere: "Presque terminé",
42
- autoGenerate: "Générer automatiquement",
43
- bestPractices: "bonnes pratiques",
44
- cancelled: "La génération a été annulée.",
45
- characterCount: "{current}/{minLength}-{maxLength} caractères",
46
- charactersLeft: ", {characters} restants",
47
- charactersToGo: ", encore {characters}",
48
- charactersTooMany: ", {characters} en trop",
49
- checksPassing: "{current}/{max} vérifications réussies",
50
- chooseExistingImage: "Choisir un élément existant",
51
- createNewImage: "Créer un élément",
52
- generationFailed: "Impossible de générer cette valeur. Réessayez.",
53
- good: "Bon",
54
- image: "Image",
55
- imageAutoGenerationTip:
56
- "Générez une image à partir du document actuel ou choisissez-en une manuellement.",
57
- imageSourceTip: "ou glissez-déposez un fichier.",
58
- imageUnavailable: "L’image référencée n’est pas disponible.",
59
- inspectImage: "Inspecter l’image",
60
- lengthTipDescription:
61
- "Ceci devrait contenir entre {minLength} et {maxLength} caractères. Pour obtenir de l’aide pour rédiger des descriptions meta de qualité, consultez les ",
62
- lengthTipTitle:
63
- "Ceci devrait contenir entre {minLength} et {maxLength} caractères. Pour obtenir de l’aide pour rédiger des titres meta de qualité, consultez les ",
64
- missing: "Manquant",
65
- noImage: "Aucune image",
66
- or: "ou",
67
- preview: "Aperçu",
68
- previewDescription:
69
- "Les résultats exacts peuvent varier en fonction du contenu et de la pertinence de la recherche.",
70
- removeImage: "Supprimer l’image",
71
- selectImage: "Sélectionner une image",
72
- tooLong: "Trop long",
73
- tooShort: "Trop court",
74
- title: "Titre",
75
- description: "Description",
76
- },
77
- ar: {
78
- almostThere: "أوشكت على الانتهاء",
79
- autoGenerate: "إنشاء تلقائي",
80
- bestPractices: "أفضل الممارسات",
81
- cancelled: "تم إلغاء الإنشاء.",
82
- characterCount: "{current}/{minLength}-{maxLength} حرفًا",
83
- charactersLeft: "، متبقٍ {characters}",
84
- charactersToGo: "، يلزم {characters}",
85
- charactersTooMany: "، زائد {characters}",
86
- checksPassing: "تم اجتياز {current}/{max} من الفحوصات",
87
- chooseExistingImage: "اختيار صورة موجودة",
88
- createNewImage: "إنشاء صورة جديدة",
89
- description: "الوصف",
90
- generationFailed: "تعذر إنشاء هذه القيمة. حاول مرة أخرى.",
91
- good: "جيد",
92
- image: "الصورة",
93
- imageAutoGenerationTip: "أنشئ صورة من المستند الحالي أو اختر صورة يدويًا.",
94
- imageSourceTip: "أو اسحب ملفًا وأفلته.",
95
- imageUnavailable: "الصورة المشار إليها غير متاحة.",
96
- inspectImage: "فحص الصورة",
97
- lengthTipDescription:
98
- "يجب أن يتراوح هذا بين {minLength} و{maxLength} حرفًا. للحصول على مساعدة في كتابة أوصاف ميتا ذات جودة، راجع ",
99
- lengthTipTitle:
100
- "يجب أن يتراوح هذا بين {minLength} و{maxLength} حرفًا. للحصول على مساعدة في كتابة عناوين ميتا ذات جودة، راجع ",
101
- missing: "مفقود",
102
- noImage: "لا توجد صورة",
103
- or: "أو",
104
- preview: "معاينة",
105
- previewDescription: "قد تختلف النتائج الدقيقة بناءً على المحتوى وملاءمة البحث.",
106
- removeImage: "إزالة الصورة",
107
- selectImage: "اختيار صورة",
108
- title: "العنوان",
109
- tooLong: "طويل جدًا",
110
- tooShort: "قصير جدًا",
111
- },
112
- },
113
- });