@escape-game-over/atlas 0.1.68 → 0.1.69

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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/config.ts +20 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@escape-game-over/atlas",
3
- "version": "0.1.68",
3
+ "version": "0.1.69",
4
4
  "type": "module",
5
5
  "description": "Typed, data-driven machinery for static multi-locale, multi-deployment Astro sites.",
6
6
  "private": false,
@@ -34,7 +34,7 @@
34
34
  "README.md"
35
35
  ],
36
36
  "engines": {
37
- "node": ">=22.12.0"
37
+ "node": ">=24.0.0"
38
38
  },
39
39
  "scripts": {
40
40
  "test": "npm run test:types && npm run test:unit && npm run test:examples",
package/src/config.ts CHANGED
@@ -2,20 +2,21 @@ import type { Fonts } from "./fonts.ts";
2
2
  import type { LlmsConfig } from "./llms.ts";
3
3
  import type { RobotsConfig } from "./robots.ts";
4
4
  import type { SitemapConfig } from "./sitemap.ts";
5
- import type { StringKeys } from "./types.ts";
5
+ import type { NoExcessKeys, StringKeys } from "./types.ts";
6
6
 
7
7
  export interface LocaleMeta {
8
8
  /** Name of the language, written in that language. */
9
9
  readonly label: string;
10
10
  // No language tag here: the locale's own key is the tag. One identifier,
11
11
  // used for the URL segment, `lang`, `hreflang` and `og:locale` alike.
12
- readonly dir: "ltr" | "rtl";
12
+ // No `dir` either: writing direction follows from the tag too.
13
13
  }
14
14
 
15
15
  /** `LocaleMeta` after defaults are filled in. */
16
16
  export interface ResolvedLocaleMeta {
17
17
  readonly label: string;
18
18
  readonly htmlLang: string;
19
+ /** Derived: the writing direction of the tag's script, from `Intl`. */
19
20
  readonly dir: "ltr" | "rtl";
20
21
  /** Derived: `htmlLang` with `-` swapped for `_`, which is the OG form. */
21
22
  readonly ogLocale: string;
@@ -55,7 +56,7 @@ interface MalformedLanguageTag<T extends string> {
55
56
  type ValidateLocales<T> = {
56
57
  [K in StringKeys<T>]: [LanguageTag<K>] extends [never]
57
58
  ? MalformedLanguageTag<K>
58
- : LocaleMeta;
59
+ : LocaleMeta & NoExcessKeys<T[K], keyof LocaleMeta>;
59
60
  };
60
61
 
61
62
  export interface RoutingConfig<L extends string> {
@@ -156,10 +157,9 @@ export function defineSiteConfig<
156
157
  /**
157
158
  * What a project may restate about a locale.
158
159
  *
159
- * `dir` is deliberately not here: writing direction is a fact about the script a
160
- * language is written in, not a choice a deployment makes. Greek is
161
- * left-to-right for everybody, and a project that could say otherwise would only
162
- * ever be wrong. The label is the one part that is a matter of taste.
160
+ * Only the label: writing direction is a fact about the script a language is
161
+ * written in, not a choice a deployment makes, so it is derived from the tag.
162
+ * The label is the one part that is a matter of taste.
163
163
  */
164
164
  export type LocaleMetaOverride = Pick<LocaleMeta, "label">;
165
165
 
@@ -184,6 +184,8 @@ export interface LocaleNotEnabled<L extends string> {
184
184
  *
185
185
  * The locale key is the language tag, and `ogLocale` is that tag with `-`
186
186
  * swapped for `_` — Open Graph writes `en_US` where BCP 47 writes `en-US`.
187
+ * `dir` comes from the tag's script, so `ar-EG` and `az-Arab-IR` are
188
+ * right-to-left and `az-AZ` is not.
187
189
  */
188
190
  export function mergeLocaleMeta<L extends string>(
189
191
  base: Readonly<Record<L, LocaleMeta>>,
@@ -199,10 +201,20 @@ export function mergeLocaleMeta<L extends string>(
199
201
  const meta = { ...defaults, ...overrides?.[locale] };
200
202
  merged[locale] = {
201
203
  label: meta.label,
202
- dir: meta.dir,
204
+ dir: writingDirection(locale),
203
205
  htmlLang: locale,
204
206
  ogLocale: locale.replace(/-/g, "_"),
205
207
  };
206
208
  }
207
209
  return merged as Readonly<Record<L, ResolvedLocaleMeta>>;
208
210
  }
211
+
212
+ function writingDirection(tag: string): "ltr" | "rtl" {
213
+ const direction = new Intl.Locale(tag).getTextInfo().direction;
214
+ if (direction === undefined) {
215
+ throw new Error(
216
+ `This runtime cannot tell the writing direction of "${tag}".`
217
+ );
218
+ }
219
+ return direction;
220
+ }