@byline/i18n 4.11.1 → 4.12.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.
package/README.md CHANGED
@@ -17,7 +17,7 @@ The package bundles every official Byline admin translation as a JSON file under
17
17
  ## Three entry points
18
18
 
19
19
  ```ts
20
- import { mergeTranslations, createFormatter, resolveInterfaceLocale } from '@byline/i18n'
20
+ import { mergeTranslations, createFormatter, resolveAdminLocale } from '@byline/i18n'
21
21
  import { I18nProvider, useTranslation, LanguageMenu } from '@byline/i18n/react'
22
22
  import { adminTranslations, en } from '@byline/i18n/admin'
23
23
  ```
@@ -30,19 +30,19 @@ import { adminTranslations, en } from '@byline/i18n/admin'
30
30
 
31
31
  ```ts
32
32
  // apps/your-app/byline/admin.config.ts
33
- import { defineClientConfig } from '@byline/core'
33
+ import { defineAdminConfig } from '@byline/core'
34
34
  import { adminTranslations } from '@byline/i18n/admin'
35
35
 
36
- defineClientConfig({
36
+ defineAdminConfig({
37
37
  i18n: {
38
- interface: {
38
+ admin: {
39
39
  defaultLocale: 'en',
40
40
  locales: ['en'],
41
41
  },
42
42
  // … content locales as before
43
43
  translations: adminTranslations({ locales: ['en'] }),
44
44
  },
45
- // … the rest of your client config
45
+ // … the rest of your admin config
46
46
  })
47
47
  ```
48
48
 
@@ -52,7 +52,7 @@ defineClientConfig({
52
52
  import { adminTranslations } from '@byline/i18n/admin'
53
53
 
54
54
  i18n: {
55
- interface: { defaultLocale: 'en', locales: ['en', 'fr'] },
55
+ admin: { defaultLocale: 'en', locales: ['en', 'fr'] },
56
56
  translations: adminTranslations({ locales: ['en', 'fr'] }),
57
57
  }
58
58
  ```
@@ -63,7 +63,7 @@ The set of bundled locales is exported as `bundledLocales` for hosts that want t
63
63
  import { adminTranslations, bundledLocales } from '@byline/i18n/admin'
64
64
 
65
65
  i18n: {
66
- interface: { defaultLocale: 'en', locales: [...bundledLocales] },
66
+ admin: { defaultLocale: 'en', locales: [...bundledLocales] },
67
67
  translations: adminTranslations({ locales: bundledLocales }),
68
68
  }
69
69
  ```
@@ -72,7 +72,7 @@ i18n: {
72
72
 
73
73
  ## Plugin contributions
74
74
 
75
- A plugin (richtext extension, custom field, AI tool, …) ships its own JSON files inside its own package and exposes a factory matching `adminTranslations`'s shape — takes `{ locales }`, returns a `TranslationBundle` for the plugin's own namespace. The host merges them in `defineClientConfig`:
75
+ A plugin (richtext extension, custom field, AI tool, …) ships its own JSON files inside its own package and exposes a factory matching `adminTranslations`'s shape — takes `{ locales }`, returns a `TranslationBundle` for the plugin's own namespace. The host merges them in `defineAdminConfig`:
76
76
 
77
77
  ```ts
78
78
  import { mergeTranslations } from '@byline/i18n'
@@ -80,7 +80,7 @@ import { adminTranslations } from '@byline/i18n/admin'
80
80
  import { aiTranslations } from '@byline/ai/i18n'
81
81
 
82
82
  i18n: {
83
- interface: { defaultLocale: 'en', locales: ['en', 'fr'] },
83
+ admin: { defaultLocale: 'en', locales: ['en', 'fr'] },
84
84
  translations: mergeTranslations(
85
85
  adminTranslations({ locales: ['en', 'fr'] }),
86
86
  aiTranslations({ locales: ['en', 'fr'] }),
@@ -88,7 +88,7 @@ i18n: {
88
88
  }
89
89
  ```
90
90
 
91
- A plugin that ships a locale the host hasn't enabled is harmless — the plugin's factory simply returns nothing for that code, the merge produces an empty entry for it, and the boot validator gates against `i18n.interface.locales` anyway.
91
+ A plugin that ships a locale the host hasn't enabled is harmless — the plugin's factory simply returns nothing for that code, the merge produces an empty entry for it, and the boot validator gates against `i18n.admin.locales` anyway.
92
92
 
93
93
  `mergeTranslations` is associative + deterministic; later sources override earlier ones at the `(locale, namespace, key)` grain, and a `MergeOptions.onCollision` callback is available for surfacing conflicts during development.
94
94
 
@@ -138,12 +138,12 @@ In a TanStack Start host, `resolveServerTranslator(namespace)` (provided by `@by
138
138
 
139
139
  ## Locale resolution cascade
140
140
 
141
- `resolveInterfaceLocale` is the same pure cascade run on client and server, so SSR and hydration produce the same answer:
141
+ `resolveAdminLocale` is the same pure cascade run on client and server, so SSR and hydration produce the same answer:
142
142
 
143
143
  ```ts
144
- import { resolveInterfaceLocale } from '@byline/i18n'
144
+ import { resolveAdminLocale } from '@byline/i18n'
145
145
 
146
- const activeLocale = resolveInterfaceLocale({
146
+ const activeLocale = resolveAdminLocale({
147
147
  locales: ['en', 'fr'],
148
148
  defaultLocale: 'en',
149
149
  preferred: actor?.admin_user?.preferred_locale,
@@ -36,9 +36,9 @@ export interface AdminTranslationsOptions {
36
36
  * ```ts
37
37
  * import { adminTranslations } from '@byline/i18n/admin'
38
38
  *
39
- * defineClientConfig({
39
+ * defineAdminConfig({
40
40
  * i18n: {
41
- * interface: { defaultLocale: 'en', locales: ['en', 'fr'] },
41
+ * admin: { defaultLocale: 'en', locales: ['en', 'fr'] },
42
42
  * translations: adminTranslations({ locales: ['en', 'fr'] }),
43
43
  * },
44
44
  * })
package/dist/index.d.ts CHANGED
@@ -26,8 +26,8 @@
26
26
  */
27
27
  export { createFormatter } from './formatter.js';
28
28
  export { mergeTranslations } from './merge.js';
29
- export { resolveInterfaceLocale } from './resolve.js';
29
+ export { resolveAdminLocale } from './resolve.js';
30
30
  export type { Formatter, FormatterOptions, MissingTranslationEvent, } from './formatter.js';
31
31
  export type { MergeOptions, TranslationCollision } from './merge.js';
32
- export type { ResolveInterfaceLocaleOptions } from './resolve.js';
32
+ export type { ResolveAdminLocaleOptions } from './resolve.js';
33
33
  export type { LocaleCode, LocaleDefinition, MessageKey, Namespace, NamespaceTranslations, TranslationBundle, TranslationValues, } from './types.js';
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { createFormatter } from "./formatter.js";
2
2
  export { mergeTranslations } from "./merge.js";
3
- export { resolveInterfaceLocale } from "./resolve.js";
3
+ export { resolveAdminLocale } from "./resolve.js";
package/dist/resolve.d.ts CHANGED
@@ -6,10 +6,10 @@
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
8
  import type { LocaleCode } from './types.js';
9
- export interface ResolveInterfaceLocaleOptions {
10
- /** Permitted locale set — from `i18n.interface.locales`. */
9
+ export interface ResolveAdminLocaleOptions {
10
+ /** Permitted locale set — from `i18n.admin.locales`. */
11
11
  locales: readonly LocaleCode[];
12
- /** Last-resort fallback — from `i18n.interface.defaultLocale`. */
12
+ /** Last-resort fallback — from `i18n.admin.defaultLocale`. */
13
13
  defaultLocale: LocaleCode;
14
14
  /** `admin_users.preferred_locale` for the authenticated request, if any. */
15
15
  preferred?: LocaleCode | null;
@@ -18,4 +18,4 @@ export interface ResolveInterfaceLocaleOptions {
18
18
  /** Raw `Accept-Language` request header. */
19
19
  acceptLanguage?: string | null;
20
20
  }
21
- export declare function resolveInterfaceLocale(options: ResolveInterfaceLocaleOptions): LocaleCode;
21
+ export declare function resolveAdminLocale(options: ResolveAdminLocaleOptions): LocaleCode;
package/dist/resolve.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { match } from "@formatjs/intl-localematcher";
2
2
  import negotiator_0 from "negotiator";
3
- function resolveInterfaceLocale(options) {
3
+ function resolveAdminLocale(options) {
4
4
  const { locales, defaultLocale, preferred, cookie, acceptLanguage } = options;
5
5
  if (null != preferred && locales.includes(preferred)) return preferred;
6
6
  if (null != cookie && locales.includes(cookie)) return cookie;
@@ -25,4 +25,4 @@ function negotiateAcceptLanguage(header, locales, defaultLocale) {
25
25
  return null;
26
26
  }
27
27
  }
28
- export { resolveInterfaceLocale };
28
+ export { resolveAdminLocale };
package/dist/types.d.ts CHANGED
@@ -8,13 +8,13 @@
8
8
  /**
9
9
  * Locale code — kept as a plain `string` so the package stays open to
10
10
  * any BCP 47 tag (`en`, `pt-BR`, `zh-Hans-CN`). The host's
11
- * `i18n.interface.locales` config is the canonical allow-list at
11
+ * `i18n.admin.locales` config is the canonical allow-list at
12
12
  * runtime; the resolver / validator narrow against it.
13
13
  */
14
14
  export type LocaleCode = string;
15
15
  /**
16
16
  * Lightweight locale definition used by `<LanguageMenu>` to render the
17
- * dropdown. The `code` matches a string in `i18n.interface.locales`;
17
+ * dropdown. The `code` matches a string in `i18n.admin.locales`;
18
18
  * the `nativeName` is what the user sees ("English", "Español",
19
19
  * "Français", "Deutsch", "日本語").
20
20
  */
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "private": false,
4
4
  "type": "module",
5
5
  "license": "MPL-2.0",
6
- "version": "4.11.1",
6
+ "version": "4.12.0",
7
7
  "engines": {
8
8
  "node": ">=20.9.0"
9
9
  },
@@ -53,29 +53,29 @@
53
53
  "dependencies": {
54
54
  "@formatjs/intl-localematcher": "^0.8.13",
55
55
  "clsx": "^2.1.1",
56
- "intl-messageformat": "^11.2.12",
56
+ "intl-messageformat": "^11.2.13",
57
57
  "negotiator": "^1.0.0",
58
- "@byline/ui": "4.11.1"
58
+ "@byline/ui": "4.12.0"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "react": "^19.0.0",
62
62
  "react-dom": "^19.0.0"
63
63
  },
64
64
  "devDependencies": {
65
- "@biomejs/biome": "2.5.4",
65
+ "@biomejs/biome": "2.5.6",
66
66
  "@rsbuild/plugin-react": "^2.1.0",
67
67
  "@rslib/core": "^0.23.2",
68
68
  "@types/negotiator": "^0.6.4",
69
- "@types/node": "^26.1.1",
70
- "@types/react": "19.2.17",
71
- "@types/react-dom": "19.2.3",
72
- "@vitejs/plugin-react": "^6.0.3",
69
+ "@types/node": "^26.1.2",
70
+ "@types/react": "19.2.18",
71
+ "@types/react-dom": "19.2.4",
72
+ "@vitejs/plugin-react": "^6.0.5",
73
73
  "npm-run-all": "^4.1.5",
74
- "react": "^19.2.7",
75
- "react-dom": "^19.2.7",
74
+ "react": "^19.2.8",
75
+ "react-dom": "^19.2.8",
76
76
  "rimraf": "^6.1.3",
77
77
  "typescript": "^7.0.2",
78
- "vite": "^8.1.5",
78
+ "vite": "^8.2.0",
79
79
  "vitest": "^4.1.10"
80
80
  },
81
81
  "publishConfig": {
@@ -86,9 +86,9 @@ export interface AdminTranslationsOptions {
86
86
  * ```ts
87
87
  * import { adminTranslations } from '@byline/i18n/admin'
88
88
  *
89
- * defineClientConfig({
89
+ * defineAdminConfig({
90
90
  * i18n: {
91
- * interface: { defaultLocale: 'en', locales: ['en', 'fr'] },
91
+ * admin: { defaultLocale: 'en', locales: ['en', 'fr'] },
92
92
  * translations: adminTranslations({ locales: ['en', 'fr'] }),
93
93
  * },
94
94
  * })
package/src/index.ts CHANGED
@@ -28,14 +28,14 @@
28
28
 
29
29
  export { createFormatter } from './formatter.js'
30
30
  export { mergeTranslations } from './merge.js'
31
- export { resolveInterfaceLocale } from './resolve.js'
31
+ export { resolveAdminLocale } from './resolve.js'
32
32
  export type {
33
33
  Formatter,
34
34
  FormatterOptions,
35
35
  MissingTranslationEvent,
36
36
  } from './formatter.js'
37
37
  export type { MergeOptions, TranslationCollision } from './merge.js'
38
- export type { ResolveInterfaceLocaleOptions } from './resolve.js'
38
+ export type { ResolveAdminLocaleOptions } from './resolve.js'
39
39
  export type {
40
40
  LocaleCode,
41
41
  LocaleDefinition,
@@ -8,14 +8,14 @@
8
8
 
9
9
  import { describe, expect, it } from 'vitest'
10
10
 
11
- import { resolveInterfaceLocale } from './resolve.js'
11
+ import { resolveAdminLocale } from './resolve.js'
12
12
 
13
13
  const locales = ['en', 'fr', 'es']
14
14
  const defaultLocale = 'en'
15
15
 
16
- describe('resolveInterfaceLocale — tier 1 (preferred)', () => {
16
+ describe('resolveAdminLocale — tier 1 (preferred)', () => {
17
17
  it('wins over every other signal when set and valid', () => {
18
- const out = resolveInterfaceLocale({
18
+ const out = resolveAdminLocale({
19
19
  locales,
20
20
  defaultLocale,
21
21
  preferred: 'fr',
@@ -26,7 +26,7 @@ describe('resolveInterfaceLocale — tier 1 (preferred)', () => {
26
26
  })
27
27
 
28
28
  it('falls through when preferred is not in the permitted set', () => {
29
- const out = resolveInterfaceLocale({
29
+ const out = resolveAdminLocale({
30
30
  locales,
31
31
  defaultLocale,
32
32
  preferred: 'de',
@@ -36,7 +36,7 @@ describe('resolveInterfaceLocale — tier 1 (preferred)', () => {
36
36
  })
37
37
 
38
38
  it('falls through when preferred is null', () => {
39
- const out = resolveInterfaceLocale({
39
+ const out = resolveAdminLocale({
40
40
  locales,
41
41
  defaultLocale,
42
42
  preferred: null,
@@ -46,9 +46,9 @@ describe('resolveInterfaceLocale — tier 1 (preferred)', () => {
46
46
  })
47
47
  })
48
48
 
49
- describe('resolveInterfaceLocale — tier 2 (cookie)', () => {
49
+ describe('resolveAdminLocale — tier 2 (cookie)', () => {
50
50
  it('wins over Accept-Language', () => {
51
- const out = resolveInterfaceLocale({
51
+ const out = resolveAdminLocale({
52
52
  locales,
53
53
  defaultLocale,
54
54
  cookie: 'es',
@@ -58,7 +58,7 @@ describe('resolveInterfaceLocale — tier 2 (cookie)', () => {
58
58
  })
59
59
 
60
60
  it('falls through when cookie points at a removed locale', () => {
61
- const out = resolveInterfaceLocale({
61
+ const out = resolveAdminLocale({
62
62
  locales,
63
63
  defaultLocale,
64
64
  cookie: 'de',
@@ -68,7 +68,7 @@ describe('resolveInterfaceLocale — tier 2 (cookie)', () => {
68
68
  })
69
69
 
70
70
  it('falls through when cookie is null', () => {
71
- const out = resolveInterfaceLocale({
71
+ const out = resolveAdminLocale({
72
72
  locales,
73
73
  defaultLocale,
74
74
  cookie: null,
@@ -78,9 +78,9 @@ describe('resolveInterfaceLocale — tier 2 (cookie)', () => {
78
78
  })
79
79
  })
80
80
 
81
- describe('resolveInterfaceLocale — tier 3 (Accept-Language)', () => {
81
+ describe('resolveAdminLocale — tier 3 (Accept-Language)', () => {
82
82
  it('picks the best match from the header', () => {
83
- const out = resolveInterfaceLocale({
83
+ const out = resolveAdminLocale({
84
84
  locales,
85
85
  defaultLocale,
86
86
  acceptLanguage: 'fr-CA;q=0.9, fr;q=0.8, en;q=0.5',
@@ -89,7 +89,7 @@ describe('resolveInterfaceLocale — tier 3 (Accept-Language)', () => {
89
89
  })
90
90
 
91
91
  it('falls back to default when no header language is in the permitted set', () => {
92
- const out = resolveInterfaceLocale({
92
+ const out = resolveAdminLocale({
93
93
  locales,
94
94
  defaultLocale,
95
95
  acceptLanguage: 'de;q=0.9, ja;q=0.5',
@@ -98,7 +98,7 @@ describe('resolveInterfaceLocale — tier 3 (Accept-Language)', () => {
98
98
  })
99
99
 
100
100
  it('handles malformed headers gracefully', () => {
101
- const out = resolveInterfaceLocale({
101
+ const out = resolveAdminLocale({
102
102
  locales,
103
103
  defaultLocale,
104
104
  acceptLanguage: 'this-is-not-a-valid-header',
@@ -109,14 +109,14 @@ describe('resolveInterfaceLocale — tier 3 (Accept-Language)', () => {
109
109
  })
110
110
  })
111
111
 
112
- describe('resolveInterfaceLocale — tier 4 (default)', () => {
112
+ describe('resolveAdminLocale — tier 4 (default)', () => {
113
113
  it('returns defaultLocale when every other tier produces nothing', () => {
114
- const out = resolveInterfaceLocale({ locales, defaultLocale })
114
+ const out = resolveAdminLocale({ locales, defaultLocale })
115
115
  expect(out).toBe('en')
116
116
  })
117
117
 
118
118
  it('returns defaultLocale when every signal is empty', () => {
119
- const out = resolveInterfaceLocale({
119
+ const out = resolveAdminLocale({
120
120
  locales,
121
121
  defaultLocale,
122
122
  preferred: null,
package/src/resolve.ts CHANGED
@@ -29,10 +29,10 @@ import Negotiator from 'negotiator'
29
29
 
30
30
  import type { LocaleCode } from './types.js'
31
31
 
32
- export interface ResolveInterfaceLocaleOptions {
33
- /** Permitted locale set — from `i18n.interface.locales`. */
32
+ export interface ResolveAdminLocaleOptions {
33
+ /** Permitted locale set — from `i18n.admin.locales`. */
34
34
  locales: readonly LocaleCode[]
35
- /** Last-resort fallback — from `i18n.interface.defaultLocale`. */
35
+ /** Last-resort fallback — from `i18n.admin.defaultLocale`. */
36
36
  defaultLocale: LocaleCode
37
37
  /** `admin_users.preferred_locale` for the authenticated request, if any. */
38
38
  preferred?: LocaleCode | null
@@ -42,7 +42,7 @@ export interface ResolveInterfaceLocaleOptions {
42
42
  acceptLanguage?: string | null
43
43
  }
44
44
 
45
- export function resolveInterfaceLocale(options: ResolveInterfaceLocaleOptions): LocaleCode {
45
+ export function resolveAdminLocale(options: ResolveAdminLocaleOptions): LocaleCode {
46
46
  const { locales, defaultLocale, preferred, cookie, acceptLanguage } = options
47
47
 
48
48
  // Tier 1 — admin user preference.
package/src/types.ts CHANGED
@@ -9,14 +9,14 @@
9
9
  /**
10
10
  * Locale code — kept as a plain `string` so the package stays open to
11
11
  * any BCP 47 tag (`en`, `pt-BR`, `zh-Hans-CN`). The host's
12
- * `i18n.interface.locales` config is the canonical allow-list at
12
+ * `i18n.admin.locales` config is the canonical allow-list at
13
13
  * runtime; the resolver / validator narrow against it.
14
14
  */
15
15
  export type LocaleCode = string
16
16
 
17
17
  /**
18
18
  * Lightweight locale definition used by `<LanguageMenu>` to render the
19
- * dropdown. The `code` matches a string in `i18n.interface.locales`;
19
+ * dropdown. The `code` matches a string in `i18n.admin.locales`;
20
20
  * the `nativeName` is what the user sees ("English", "Español",
21
21
  * "Français", "Deutsch", "日本語").
22
22
  */