@uxfront/layer-docs 0.1.1 → 0.2.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.
Files changed (45) hide show
  1. package/CHANGELOG.md +114 -6
  2. package/app/components/app/AppHeaderAttribution.vue +10 -1
  3. package/app/components/content/FrameworkSwitcher.vue +1 -0
  4. package/app/components/content/GradientPageHero.vue +35 -0
  5. package/app/components/docs/DocsAsideLeftTop.vue +24 -0
  6. package/app/components/docs/DocsFrameworkSelect.vue +18 -0
  7. package/app/composables/useFramework.ts +20 -29
  8. package/app/layouts/default.vue +1 -0
  9. package/app/plugins/posthog.client.ts +24 -5
  10. package/i18n/locales/ar.json +24 -0
  11. package/i18n/locales/be.json +24 -0
  12. package/i18n/locales/bn.json +24 -0
  13. package/i18n/locales/ca.json +24 -0
  14. package/i18n/locales/ckb.json +24 -0
  15. package/i18n/locales/cs.json +24 -0
  16. package/i18n/locales/da.json +24 -0
  17. package/i18n/locales/de.json +24 -0
  18. package/i18n/locales/el.json +24 -0
  19. package/i18n/locales/en.json +1 -0
  20. package/i18n/locales/et.json +24 -0
  21. package/i18n/locales/fr.json +24 -0
  22. package/i18n/locales/he.json +24 -0
  23. package/i18n/locales/hi.json +24 -0
  24. package/i18n/locales/hy.json +24 -0
  25. package/i18n/locales/it.json +24 -0
  26. package/i18n/locales/ja.json +24 -0
  27. package/i18n/locales/kk.json +24 -0
  28. package/i18n/locales/km.json +24 -0
  29. package/i18n/locales/ko.json +24 -0
  30. package/i18n/locales/ky.json +24 -0
  31. package/i18n/locales/lb.json +24 -0
  32. package/i18n/locales/ms.json +24 -0
  33. package/i18n/locales/nb.json +24 -0
  34. package/i18n/locales/pl.json +24 -0
  35. package/i18n/locales/ru.json +24 -0
  36. package/i18n/locales/sl.json +24 -0
  37. package/i18n/locales/sv.json +24 -0
  38. package/i18n/locales/uk.json +24 -0
  39. package/i18n/locales/ur.json +24 -0
  40. package/i18n/locales/vi.json +24 -0
  41. package/modules/optimizeDeps.ts +45 -0
  42. package/nuxt.config.ts +1 -0
  43. package/nuxt.schema.ts +359 -0
  44. package/package.json +2 -1
  45. package/utils/content.ts +85 -10
package/CHANGELOG.md CHANGED
@@ -1,14 +1,109 @@
1
1
  # @uxfront/layer-docs
2
2
 
3
- ## 0.1.2
3
+ ## 0.2.1
4
4
 
5
5
  ### Patch Changes
6
6
 
7
- - Fix `nuxt typecheck` failure in `AppHeaderCTA.vue`: the config module seeds a
8
- partial `header` (`{ title }`), so defu narrows the resolved `AppConfig` header
9
- to `{ title, logo }` and drops the array-valued `links`. Read `links` through a
10
- cast on `header` itself instead of the `.links` result, so consumers extending
11
- the layer typecheck cleanly. Runtime behaviour is unchanged.
7
+ - Stop the optional `posthog-js` peer from killing the client bundle of every consumer that omits it.
8
+
9
+ `app/plugins/posthog.client.ts` imported `posthog-js` statically at module scope while declaring it an **optional** `peerDependency`. Rollup has no module to resolve for a consumer that skipped the optional peer, so it emits the specifier as a module-scope throw:
10
+
11
+ ```js
12
+ const HB = {};
13
+ throw new Error('Could not resolve "posthog-js" imported by "@uxfront/layer-docs".');
14
+ ```
15
+
16
+ That throw runs on evaluation, before the plugin body — so neither the `analytics.enabled` guard nor the `posthog.key` guard ever executed, and the failure was not confined to analytics. The whole client entry died with it: **the site did not hydrate at all**. Every page served as a dead static document — theme toggle stuck on its loading skeleton, framework tabs inert, no client-side routing, `localStorage` never written — with one console error per route as the only signal. Present in `0.1.0`, `0.1.1` and `0.2.0`.
17
+
18
+ `posthog-js` is now imported dynamically, inside the branch that has already confirmed analytics is enabled and a key is provisioned. The unresolvable specifier moves out of the client entry into its own lazy chunk that a consumer without the peer never evaluates — it is emitted, prefetched at most, and never run. The import is also wrapped, which keeps the failure proportional to what failed: a missing or broken module degrades to a console warning and no analytics, instead of a dead app.
19
+
20
+ `modules/optimizeDeps` carried the same assumption from the other direction — it named `posthog-js` in `optimizeDeps.include` unconditionally, which is a hard dev-server error when the package is not installed. The hint is now added only when the dependency actually resolves.
21
+
22
+ Consumers who do not use PostHog need no changes and should upgrade. Consumers who do use it are unaffected: `$posthog()` is provided exactly as before once the client initialises.
23
+
24
+ ## 0.2.0
25
+
26
+ ### Minor Changes
27
+
28
+ - Absorb documentation-site plumbing that consumers were re-declaring by hand.
29
+
30
+ - `defineDocsCollections(sections, options)` gains `{ sitemap?, changelog? }`. With
31
+ `sitemap: true` the landing and docs collections carry `defineSitemapSchema()`;
32
+ with `changelog: true` a `changelog` collection is registered over
33
+ `changelog/*.md`. Both default to `false`, so existing single-argument calls are
34
+ unchanged. Per-locale collections are now gated on `locales.length > 0` rather
35
+ than the array's mere presence.
36
+ - 30 additional locales ship with the layer (ar, be, bn, ca, ckb, cs, da, de, el,
37
+ et, fr, he, hi, hy, it, ja, kk, km, ko, ky, lb, ms, nb, pl, ru, sl, sv, uk, ur,
38
+ vi), each complete against `en.json`.
39
+ - `nuxt.schema.ts` ships with the layer, so the Content Studio preview schema for
40
+ `app.config.ts` is described once instead of per consumer.
41
+ - New `modules/optimizeDeps` module pre-bundles the layer's own heavier runtime
42
+ dependencies; registered automatically.
43
+ - New `DocsAsideLeftTop` / `DocsFrameworkSelect` render a persistent framework
44
+ selector above the sidebar navigation, and `GradientPageHero` puts `UPageHero`
45
+ on `MorphingGradientBackground`. Both render only when the consumer opts in.
46
+
47
+ **Breaking-ish:** `useFramework()` no longer ships a built-in React/Vue/Vanilla
48
+ default list. `frameworks` is now `appConfig.docsTheme.frameworks ?? []`, making
49
+ app config the single source of truth. Sites that relied on the implicit default
50
+ must declare `docsTheme.frameworks` in their own `app.config.ts`; `FrameworkSwitcher`
51
+ renders no tab bar when the list is empty.
52
+
53
+ ### Patch Changes
54
+
55
+ - Correct the changelog so it matches what was actually published. `0.1.1` shipped
56
+ with no entry of its own while an entry for a `0.1.2` that was never published
57
+ sat at the top of the file, so consumers had no way to learn from the changelog
58
+ that `0.1.1` contains accessibility fixes for `button-name` and
59
+ `nested-interactive` violations. `0.1.1` now has a complete entry, and the
60
+ `AppHeaderCTA.vue` typecheck fix previously filed under `0.1.2` is recorded
61
+ under `0.1.0`, the release it actually shipped in.
62
+
63
+ Note: `0.2.0` was versioned by a hand `chore: bump version` commit that bypassed
64
+ `changeset version`, so it published with no changelog entry at all — the tarball
65
+ topped out at a `## 0.1.2` heading for a version that was versioned but never
66
+ published. The entry above is the accurate, reconstructed record of what `0.2.0`
67
+ actually contains, and the changelog-only correction previously filed under
68
+ `0.1.2` is folded in here because `0.2.0` is the release it shipped in. Every
69
+ heading in this file now corresponds to a version that exists on the registry.
70
+ Second occurrence of UXF-67; see UXF-168.
71
+
72
+ ## 0.1.1
73
+
74
+ ### Minor Changes
75
+
76
+ - Add `header.attribution` so a consuming app can render a partially-linked
77
+ wordmark, e.g. "uxd by UXFront" where only "UXFront" links out. The header now
78
+ owns UHeader's `#left` slot instead of `#title`, because `#title` is rendered
79
+ inside UHeader's own home link and an attribution link there would nest
80
+ anchors. Apps that do not set `attribution` render exactly as before.
81
+
82
+ ### Patch Changes
83
+
84
+ - Fix accessible names on icon-only navigation controls and hide the section
85
+ sub-header when there is nothing to switch between.
86
+
87
+ - The mobile menu toggle and the "copy page" dropdown trigger now expose
88
+ accessible names (sourced from the active locale), clearing two critical
89
+ `button-name` violations that shipped on every page. **Consumers on `0.1.0`
90
+ should upgrade** — those violations were present on every page of every
91
+ site extending this layer.
92
+ - The page footer separator is now `decorative`, clearing a serious
93
+ `nested-interactive` violation caused by focusable links inside an element
94
+ with `role="separator"`.
95
+ - The docs sub-header no longer renders when the consumer declares one section
96
+ or none, so a single-section site gets no empty bar and no extra header
97
+ height.
98
+
99
+ - Skip PostHog initialisation when no key is provisioned
100
+ (`NUXT_PUBLIC_POSTHOG_KEY` unset), instead of initialising a client that fires
101
+ requests at nothing.
102
+
103
+ Note: `0.1.1` was versioned by hand rather than through `changeset version`, so
104
+ it published as a patch even though `header.attribution` is additive and would
105
+ have produced `0.2.0`. The published number stands; the entry above is the
106
+ accurate record of its contents. See UXF-67.
12
107
 
13
108
  ## 0.1.0
14
109
 
@@ -19,3 +114,16 @@
19
114
  polish, base `main.css` (Tailwind + Nuxt UI wiring, palette-free),
20
115
  `MorphingGradientBackground`, and opt-out-gated i18n-redirect and PostHog
21
116
  plugins. Nuxt documentation stack declared as pinned `peerDependencies`.
117
+
118
+ ### Patch Changes
119
+
120
+ - Fix `nuxt typecheck` failure in `AppHeaderCTA.vue`: the config module seeds a
121
+ partial `header` (`{ title }`), so defu narrows the resolved `AppConfig` header
122
+ to `{ title, logo }` and drops the array-valued `links`. Read `links` through a
123
+ cast on `header` itself instead of the `.links` result, so consumers extending
124
+ the layer typecheck cleanly. Runtime behaviour is unchanged.
125
+
126
+ This fix was previously filed under a `## 0.1.2` heading that no published
127
+ release ever carried. It was written while the package was still named
128
+ `@uxfront/docs-theme` — a name that was never published — and it shipped in
129
+ `@uxfront/layer-docs@0.1.0`, the first release under the current name.
@@ -15,9 +15,18 @@
15
15
  * `prefix` stays plain text so the link's accessible name is exactly the brand
16
16
  * it points at — "by UXFront" would read as the link text otherwise.
17
17
  */
18
+ type Attribution = { prefix?: string; label?: string; to?: string };
19
+
18
20
  const appConfig = useAppConfig();
19
21
 
20
- const attribution = computed(() => appConfig.header?.attribution);
22
+ // Read through a local type, as `AppHeaderCTA` does for `header.links`: Nuxt's
23
+ // generated `AppConfig` prefers the shape inferred from the merged
24
+ // `app.config.ts` values over the `nuxt.schema.ts` type, so a consumer that
25
+ // declares `header` without `attribution` erases the key from the type even
26
+ // though the layer's own defaults supply it at runtime.
27
+ const attribution = computed(
28
+ () => (appConfig.header as { attribution?: Attribution } | undefined)?.attribution,
29
+ );
21
30
  </script>
22
31
 
23
32
  <template>
@@ -22,6 +22,7 @@ function select(value: string) {
22
22
  <template>
23
23
  <div class="framework-switcher">
24
24
  <div
25
+ v-if="frameworks.length"
25
26
  class="framework-switcher-tabs flex flex-wrap gap-1 mb-3 border-b border-default"
26
27
  role="tablist"
27
28
  >
@@ -0,0 +1,35 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * `UPageHero` on the layer's `MorphingGradientBackground`, usable from MDC:
4
+ *
5
+ * ```mdc
6
+ * ::gradient-page-hero
7
+ * ---
8
+ * ---
9
+ * #title
10
+ * Your headline
11
+ * ::
12
+ * ```
13
+ *
14
+ * Ships with `MorphingGradientBackground` rather than beside it: a package that
15
+ * hands you the ingredient should hand you the recipe too. The gradient's own
16
+ * base surface follows `--ui-bg`; its blob colours are the background
17
+ * component's own fixed palette, overridable per consumer by restating the
18
+ * `--color1..5` custom properties on an ancestor.
19
+ */
20
+ defineOptions({
21
+ inheritAttrs: false,
22
+ });
23
+ </script>
24
+
25
+ <template>
26
+ <MorphingGradientBackground v-slot="{ onMousemove }">
27
+ <UPageHero v-bind="$attrs" @mousemove="onMousemove">
28
+ <slot />
29
+ <template #title><slot name="title" /></template>
30
+ <template #description><slot name="description" /></template>
31
+ <template #headline><slot name="headline" /></template>
32
+ <template #links><slot name="links" /></template>
33
+ </UPageHero>
34
+ </MorphingGradientBackground>
35
+ </template>
@@ -0,0 +1,24 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Persistent framework selector above the docs sidebar navigation.
4
+ *
5
+ * Renders nothing unless the consumer declares `docsTheme.frameworks` in its
6
+ * `app.config.ts`. The in-content `FrameworkSwitcher` shares the same state,
7
+ * but per-page tabs alone scale poorly past a handful of frameworks — this is
8
+ * the always-visible control for the same preference.
9
+ */
10
+ const { frameworks } = useFramework();
11
+ const { t } = useDocusI18n();
12
+ </script>
13
+
14
+ <template>
15
+ <div v-if="frameworks.length">
16
+ <span
17
+ class="group relative w-full pr-2.5 py-1.5 flex items-center gap-1.5 text-sm text-muted cursor-default hover:text-highlighted transition-colors font-normal"
18
+ >
19
+ <span class="truncate">{{ t("docs.framework") }}</span>
20
+ </span>
21
+
22
+ <DocsFrameworkSelect class="mb-2" />
23
+ </div>
24
+ </template>
@@ -0,0 +1,18 @@
1
+ <script setup lang="ts">
2
+ const { framework, frameworks } = useFramework();
3
+
4
+ const current = computed(
5
+ () => frameworks.value.find((option) => option.value === framework.value) ?? frameworks.value[0],
6
+ );
7
+ </script>
8
+
9
+ <template>
10
+ <USelect
11
+ v-model="framework"
12
+ :items="[...frameworks]"
13
+ variant="ghost"
14
+ color="neutral"
15
+ :icon="current?.icon"
16
+ class="w-full"
17
+ />
18
+ </template>
@@ -1,11 +1,11 @@
1
1
  import { useLocalStorage } from "@vueuse/core";
2
2
 
3
3
  /**
4
- * A single selectable framework tab in the docs `FrameworkSwitcher`.
5
- * `value` doubles as the slot name and the persisted storage token; `label` is
6
- * the visible tab text; `icon` is an Iconify name. `value` is an open string so
7
- * a consumer can declare any framework set (e.g. `svelte`, `solid`, `angular`),
8
- * not just the layer's neutral default.
4
+ * A single selectable framework in the docs `FrameworkSwitcher` and the sidebar
5
+ * `DocsFrameworkSelect`. `value` doubles as the slot name and the persisted
6
+ * storage token; `label` is the visible text; `icon` is an Iconify name.
7
+ * `value` is an open string so a consumer can declare any framework set
8
+ * (e.g. `svelte`, `solid`, `angular`).
9
9
  */
10
10
  export interface FrameworkOption {
11
11
  value: string;
@@ -13,9 +13,12 @@ export interface FrameworkOption {
13
13
  icon: string;
14
14
  }
15
15
 
16
+ // Neutral, layer-owned storage key — not tied to any consuming product.
17
+ const STORAGE_KEY = "docs-theme:framework";
18
+
16
19
  /**
17
- * Neutral, brand-agnostic default framework set. A consumer overrides the whole
18
- * list — in declared order — via its `app.config.ts`:
20
+ * Reads the framework list a consumer declares — in display order — in its
21
+ * `app.config.ts`:
19
22
  *
20
23
  * ```ts
21
24
  * export default defineAppConfig({
@@ -24,42 +27,30 @@ export interface FrameworkOption {
24
27
  * { value: "react", label: "React", icon: "i-mdi-react" },
25
28
  * { value: "vue", label: "Vue", icon: "i-mdi-vuejs" },
26
29
  * { value: "svelte", label: "Svelte", icon: "i-mdi-svelte" },
27
- * // ...N frameworks
28
30
  * ],
29
31
  * },
30
32
  * });
31
33
  * ```
32
34
  *
35
+ * `docsTheme.frameworks` is the only source. Which frameworks a product
36
+ * documents is the product's fact, not the theme's, so the layer ships no
37
+ * default list; a consumer that declares none gets an empty list and the
38
+ * framework UI renders nothing.
39
+ *
33
40
  * The list is read from app config rather than merged as a layer default on
34
41
  * purpose: Nuxt's `defu` layer merge *concatenates* arrays, so a shipped default
35
- * would append to (not replace) the consumer's list. Keeping the default here
36
- * and only reading a consumer-supplied override guarantees a clean replacement,
37
- * while an app with no `frameworks` configured keeps the original behaviour.
42
+ * would append to (not replace) the consumer's list.
38
43
  */
39
- export const DEFAULT_FRAMEWORKS: readonly FrameworkOption[] = [
40
- { value: "react", label: "React", icon: "i-mdi-react" },
41
- {
42
- value: "other",
43
- label: "Vanilla",
44
- icon: "i-mdi-language-typescript",
45
- },
46
- { value: "vue", label: "Vue", icon: "i-mdi-vuejs" },
47
- ] as const;
48
-
49
- // Neutral, layer-owned storage key — not tied to any consuming product.
50
- const STORAGE_KEY = "docs-theme:framework";
51
-
52
44
  export const useFramework = () => {
53
45
  const appConfig = useAppConfig() as {
54
46
  docsTheme?: { frameworks?: FrameworkOption[] };
55
47
  };
56
48
 
57
- const frameworks = computed<readonly FrameworkOption[]>(() => {
58
- const configured = appConfig.docsTheme?.frameworks;
59
- return configured?.length ? configured : DEFAULT_FRAMEWORKS;
60
- });
49
+ const frameworks = computed<readonly FrameworkOption[]>(
50
+ () => appConfig.docsTheme?.frameworks ?? [],
51
+ );
61
52
 
62
- const framework = useLocalStorage<string>(STORAGE_KEY, frameworks.value[0]!.value, {
53
+ const framework = useLocalStorage<string>(STORAGE_KEY, frameworks.value[0]?.value ?? "", {
63
54
  initOnMounted: true,
64
55
  });
65
56
 
@@ -11,6 +11,7 @@ const isDocs = computed(() => route.path.startsWith("/docs"));
11
11
  <UPage>
12
12
  <template #left>
13
13
  <UPageAside>
14
+ <DocsAsideLeftTop />
14
15
  <DocsAsideLeftBody />
15
16
  </UPageAside>
16
17
  </template>
@@ -1,15 +1,14 @@
1
1
  import type { ConfigDefaults } from "posthog-js";
2
- import posthog from "posthog-js";
3
2
  import { defineNuxtPlugin } from "#app";
4
3
 
5
- export default defineNuxtPlugin(() => {
4
+ export default defineNuxtPlugin(async () => {
6
5
  if (import.meta.dev) {
7
- return;
6
+ return {};
8
7
  }
9
8
 
10
9
  // Consumers opt out via `app.config` (`analytics.enabled: false`).
11
10
  if (!useAppConfig().analytics?.enabled) {
12
- return;
11
+ return {};
13
12
  }
14
13
 
15
14
  const runtimeConfig = useRuntimeConfig();
@@ -17,7 +16,27 @@ export default defineNuxtPlugin(() => {
17
16
  // No key provisioned (`NUXT_PUBLIC_POSTHOG_KEY` unset) — no-op instead of
18
17
  // initialising a client that would fire requests at nothing.
19
18
  if (!runtimeConfig.public.posthog.key) {
20
- return;
19
+ return {};
20
+ }
21
+
22
+ // `posthog-js` is an OPTIONAL peer dependency. A static top-level import
23
+ // compiles to a module-scope `throw` for every consumer that omits it, and
24
+ // that throw runs before any of the guards above — killing the entire client
25
+ // bundle, not just analytics, so the site serves as a dead static document.
26
+ // Importing here keeps the unresolvable specifier behind the opt-in, and the
27
+ // catch keeps a missing or broken module a no-analytics degradation rather
28
+ // than a dead app.
29
+ let posthog;
30
+ try {
31
+ ({ default: posthog } = await import("posthog-js"));
32
+ } catch (error) {
33
+ console.warn(
34
+ "[layer-docs] analytics is enabled and a PostHog key is set, but " +
35
+ "`posthog-js` could not be loaded — continuing without analytics. " +
36
+ "Install `posthog-js` to enable it.",
37
+ error,
38
+ );
39
+ return {};
21
40
  }
22
41
 
23
42
  const posthogClient = posthog.init(runtimeConfig.public.posthog.key, {
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "أو",
4
+ "error": {
5
+ "title": "الصفحة غير موجودة",
6
+ "description": "نأسف، لكن الصفحة التي تبحث عنها غير موجودة."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "نسخ الصفحة",
12
+ "options": "خيارات نسخ إضافية",
13
+ "link": "نسخ صفحة Markdown",
14
+ "view": "عرض كـ Markdown",
15
+ "gpt": "فتح في ChatGPT",
16
+ "claude": "فتح في Claude"
17
+ },
18
+ "framework": "إطار العمل",
19
+ "links": "المجتمع",
20
+ "toc": "في هذه الصفحة",
21
+ "report": "الإبلاغ عن مشكلة",
22
+ "edit": "تحرير هذه الصفحة"
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "або",
4
+ "error": {
5
+ "title": "Старонка не знойдзена",
6
+ "description": "Прабачце, але старонка, якую вы шукаеце, не знойдзена."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "Скапіраваць старонку",
12
+ "options": "Дадатковыя параметры капіравання",
13
+ "link": "Скапіраваць Markdown-старонку",
14
+ "view": "Праглядзець як Markdown",
15
+ "gpt": "Адкрыць у ChatGPT",
16
+ "claude": "Адкрыць у Claude"
17
+ },
18
+ "framework": "Фреймворк",
19
+ "links": "Супольнасць",
20
+ "toc": "На гэтай старонцы",
21
+ "report": "Паведаміць пра праблему",
22
+ "edit": "Рэдагаваць гэтую старонку"
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "অথবা",
4
+ "error": {
5
+ "title": "পেজ খুঁজে পাওয়া যায়নি",
6
+ "description": "দুঃখিত, আপনি যে পেজটি খুঁজছেন সেটি পাওয়া যায়নি।"
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "পেজ কপি করুন",
12
+ "options": "আরও কপি অপশন",
13
+ "link": "Markdown পেজ কপি করুন",
14
+ "view": "Markdown হিসেবে দেখুন",
15
+ "gpt": "ChatGPT এ খুলুন",
16
+ "claude": "Claude এ খুলুন"
17
+ },
18
+ "framework": "ফ্রেমওয়ার্ক",
19
+ "links": "কমিউনিটি",
20
+ "toc": "এই পেজে",
21
+ "report": "সমস্যা রিপোর্ট করুন",
22
+ "edit": "এই পেজ সম্পাদনা করুন"
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "o",
4
+ "error": {
5
+ "title": "Pàgina no trobada",
6
+ "description": "Ho sentim, però la pàgina que cerques no existeix."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "Copiar pàgina",
12
+ "options": "Més opcions de còpia",
13
+ "link": "Copiar pàgina Markdown",
14
+ "view": "Veure com a Markdown",
15
+ "gpt": "Obrir a ChatGPT",
16
+ "claude": "Obrir a Claude"
17
+ },
18
+ "framework": "Framework",
19
+ "links": "Comunitat",
20
+ "toc": "En aquesta pàgina",
21
+ "report": "Informar d'un problema",
22
+ "edit": "Editar aquesta pàgina"
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "یان",
4
+ "error": {
5
+ "title": "پەڕە نەدۆزرایەوە",
6
+ "description": "بەداخەوە، ئەم پەڕەیە نەدۆزرایەوە."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "کۆپیکردنی پەڕە",
12
+ "options": "بژاردەی زیاتری لەبەرگرتنەوە",
13
+ "link": "کۆپیکردنی پەڕەی Markdown",
14
+ "view": "بینین وەک Markdown",
15
+ "gpt": "کردنەوە لە ChatGPT",
16
+ "claude": "کردنەوە لە Claude"
17
+ },
18
+ "framework": "چوارچێوە",
19
+ "links": "کۆمەڵگا",
20
+ "toc": "لەم پەڕەدا",
21
+ "report": "ڕاپۆرتکردنی کێشە",
22
+ "edit": "دەستکاریکردنی ئەم پەڕەیە"
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "nebo",
4
+ "error": {
5
+ "title": "Stránka nenalezena",
6
+ "description": "Je nám líto, ale stránka, kterou hledáte, nebyla nalezena."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "Kopírovat stránku",
12
+ "options": "Další možnosti kopírování",
13
+ "link": "Kopírovat Markdown stránku",
14
+ "view": "Zobrazit jako Markdown",
15
+ "gpt": "Otevřít v ChatGPT",
16
+ "claude": "Otevřít v Claude"
17
+ },
18
+ "framework": "Framework",
19
+ "links": "Komunita",
20
+ "toc": "Na této stránce",
21
+ "report": "Nahlásit problém",
22
+ "edit": "Upravit tuto stránku"
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "eller",
4
+ "error": {
5
+ "title": "Side ikke fundet",
6
+ "description": "Vi beklager, men siden du leder efter kunne ikke findes."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "Kopier side",
12
+ "options": "Flere kopieringsmuligheder",
13
+ "link": "Kopier Markdown side",
14
+ "view": "Vis som Markdown",
15
+ "gpt": "Åbn i ChatGPT",
16
+ "claude": "Åbn i Claude"
17
+ },
18
+ "framework": "Framework",
19
+ "links": "Fællesskab",
20
+ "toc": "På denne side",
21
+ "report": "Rapporter et problem",
22
+ "edit": "Rediger denne side"
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "oder",
4
+ "error": {
5
+ "title": "Seite nicht gefunden",
6
+ "description": "Es tut uns leid, aber diese Seite konnte nicht gefunden werden."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "Seite kopieren",
12
+ "options": "Weitere Kopieroptionen",
13
+ "link": "Markdown-Seite kopieren",
14
+ "view": "Als Markdown anzeigen",
15
+ "gpt": "In ChatGPT öffnen",
16
+ "claude": "In Claude öffnen"
17
+ },
18
+ "framework": "Framework",
19
+ "links": "Community",
20
+ "toc": "Auf dieser Seite",
21
+ "report": "Problem melden",
22
+ "edit": "Diese Seite bearbeiten"
23
+ }
24
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "ή",
4
+ "error": {
5
+ "title": "Η σελίδα δεν βρέθηκε",
6
+ "description": "Λυπούμαστε, αλλά η σελίδα που αναζητάτε δεν υπάρχει."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "Αντιγραφή σελίδας",
12
+ "options": "Περισσότερες επιλογές αντιγραφής",
13
+ "link": "Αντιγραφή σελίδας Markdown",
14
+ "view": "Προβολή ως Markdown",
15
+ "gpt": "Άνοιγμα στο ChatGPT",
16
+ "claude": "Άνοιγμα στο Claude"
17
+ },
18
+ "framework": "Framework",
19
+ "links": "Κοινότητα",
20
+ "toc": "Σε αυτή τη σελίδα",
21
+ "report": "Αναφορά προβλήματος",
22
+ "edit": "Επεξεργασία αυτής της σελίδας"
23
+ }
24
+ }
@@ -15,6 +15,7 @@
15
15
  "gpt": "Open in ChatGPT",
16
16
  "claude": "Open in Claude"
17
17
  },
18
+ "framework": "Framework",
18
19
  "links": "Community",
19
20
  "toc": "On this page",
20
21
  "report": "Report an issue",
@@ -0,0 +1,24 @@
1
+ {
2
+ "common": {
3
+ "or": "või",
4
+ "error": {
5
+ "title": "Lehekülge ei leitud",
6
+ "description": "Vabandame, kuid otsitavat lehekülge ei leitud."
7
+ }
8
+ },
9
+ "docs": {
10
+ "copy": {
11
+ "page": "Kopeeri lehekülg",
12
+ "options": "Rohkem kopeerimisvalikuid",
13
+ "link": "Kopeeri Markdown lehekülg",
14
+ "view": "Vaata Markdownina",
15
+ "gpt": "Ava ChatGPT-s",
16
+ "claude": "Ava Claude'is"
17
+ },
18
+ "framework": "Raamistik",
19
+ "links": "Kogukond",
20
+ "toc": "Sellel lehel",
21
+ "report": "Teata probleemist",
22
+ "edit": "Muuda seda lehekülge"
23
+ }
24
+ }