@iyulab/modern-app 0.25.0 โ†’ 0.26.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/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.26.0] - 2026-09-23
4
+
5
+ ### Changed
6
+
7
+ - ๐Ÿ”ด **Built-in strings follow `Locale` of `@iyulab/components` โ€” the language is chosen once, with
8
+ `Locale.set()`.** This package kept a registry of its own (`registerLocale`/`setDefaultLocale`)
9
+ while the primitives and `@iyulab/flex-table` follow `Locale`, so an app that set the language
10
+ once got the shell's `Toggle sidebar`/`Toggle menu`/`Close` labels, the back link and empty-state
11
+ copy in English in the middle of a translated screen โ€” silently. The strings now live in a
12
+ `Locale.namespace('modern-app')`, and resolve through the same chain as the primitives (so
13
+ `lang="zh"` reaches a `zh-CN` table). An element's own `locale` attribute still overrides the
14
+ active language for that element.
15
+
16
+ ### Added
17
+
18
+ - **`modernAppLocale`** โ€” the namespace handle, for translations:
19
+ `modernAppLocale.register('ko', { back: '๋’ค๋กœ' })`, the same shape as `flexTableLocale.register`.
20
+ `wizardStepAnnouncement` is a template there (`'{total}๋‹จ๊ณ„ ์ค‘ {index}๋‹จ๊ณ„: {label}'`).
21
+ **`ModernAppMessageKey`** is its key type.
22
+
23
+ ### Deprecated
24
+
25
+ - **`registerLocale` and `setDefaultLocale`.** Both keep working: `registerLocale` forwards to
26
+ the namespace (a function-valued `wizardStepAnnouncement` still works), and a `setDefaultLocale()`
27
+ call still takes precedence over `Locale` until it is called with `undefined` โ€” an app that
28
+ calls both with the same language sees no change and can drop `setDefaultLocale` at its leisure.
29
+
30
+ โš  **Requires `@iyulab/components` 1.45.0** (for `LocaleNamespace.textIn`, which resolves an
31
+ element's own `locale`).
32
+
3
33
  ## [0.25.0] - 2026-09-23
4
34
 
5
35
  ### Added
package/README.md CHANGED
@@ -118,6 +118,30 @@ import { translate } from '@iyulab/modern-app';
118
118
  html`<p>${translate('common::greeting')}</p>`;
119
119
  ```
120
120
 
121
+ ### Built-in strings
122
+
123
+ The package's own strings โ€” the page header's back link, empty-state copy, the shell's toggle and
124
+ close labels, the wizard's buttons and step announcement โ€” are English by default and live in the
125
+ `modern-app` namespace of `@iyulab/components`' `Locale`. Register translations there and pick the
126
+ language once, with `Locale.set()`; the primitives and `@iyulab/flex-table` follow the same call:
127
+
128
+ ```typescript
129
+ import { Locale } from '@iyulab/components';
130
+ import { modernAppLocale } from '@iyulab/modern-app';
131
+
132
+ modernAppLocale.register('ko', {
133
+ back: '๋’ค๋กœ',
134
+ toggleSidebar: '์‚ฌ์ด๋“œ๋ฐ” ์ ‘๊ธฐ/ํŽผ์น˜๊ธฐ',
135
+ wizardStepAnnouncement: '{total}๋‹จ๊ณ„ ์ค‘ {index}๋‹จ๊ณ„: {label}',
136
+ });
137
+ Locale.set('ko');
138
+ ```
139
+
140
+ A partial table is enough โ€” untranslated keys fall back to English. An element's own `locale`
141
+ attribute overrides the active language for that element. `registerLocale`/`setDefaultLocale` still
142
+ work but are deprecated: a `setDefaultLocale()` call takes precedence over `Locale` until it is
143
+ called with `undefined`.
144
+
121
145
  ### ๋ถ€ํŒ… ์ธ์ฆ ๊ฒŒ์ดํŠธ (`auth`)
122
146
 
123
147
  ์…ธ์„ ๋งŒ๋“ค๊ธฐ ์ „์— ์„ธ์…˜์„ ํŒ์ •ํ•œ๋‹ค. ์†Œ๋น„์•ฑ์ด `app.load()` ์•ž๋‹จ์— ์†์œผ๋กœ ์งœ๋˜ "me ์กฐํšŒ โ†’ ๋ฏธ์ธ์ฆ์ด๋ฉด ๋กœ๊ทธ์ธ, ์ธ์ฆ์ด๋ฉด ์•ฑ ๋กœ๋“œ" ๊ฒŒ์ดํŠธ๋ฅผ ํ‘œ์ค€ํ™”ํ•œ๋‹ค. ์„ธ์…˜ ์กฐํšŒ/๋กœ๊ทธ์ธ HTTP ๋Š” `@iyulab/enterprise` ์˜ `createAuthClient` ๊ฐ€, ์„ธ์…˜-์ค‘ 401 ์€ `createODataService` ์˜ `onUnauthorized` ๊ฐ€ ๋‹ด๋‹นํ•œ๋‹ค(ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜๋งŒ ์†Œ์œ ).
@@ -19,7 +19,7 @@ type ElementParts = 'host' | 'icon' | 'title' | 'description' | 'actions';
19
19
  * ```
20
20
  *
21
21
  * โš **๊ธฐ๋ณธ ๋ฌธ๊ตฌ๋Š” ์˜์–ด๋‹ค** โ€” ์ด ํŒจํ‚ค์ง€๋Š” ๋ฒ”์šฉ ์ธต์ด๋ผ ํŠน์ • ์–ธ์–ด๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค.
22
- * ํ•œ๊ตญ์–ด๋Š” `registerLocale('ko', โ€ฆ)` ๋กœ ์†Œ๋น„์ž๊ฐ€ ๋“ฑ๋กํ•˜๊ณ , ํ™”๋ฉด๋ณ„๋กœ ๋ฎ์œผ๋ ค๋ฉด
22
+ * ํ•œ๊ตญ์–ด๋Š” `modernAppLocale.register('ko', โ€ฆ)` ๋กœ ์†Œ๋น„์ž๊ฐ€ ๋“ฑ๋กํ•˜๊ณ (์–ธ์–ด๋Š” `Locale.set()`), ํ™”๋ฉด๋ณ„๋กœ ๋ฎ์œผ๋ ค๋ฉด
23
23
  * `title`ยท`description` ์„ ์ค€๋‹ค.
24
24
  *
25
25
  * โ˜…์ด ์ค„์€ ยซํ•œ๊ตญ์–ด๋‹คยป๋ผ๊ณ  ์ ํ˜€ ์žˆ์—ˆ๊ณ  **๊ฐ™์€ ํŒŒ์ผ์˜ `locale` ํ”„๋กœํผํ‹ฐ ์ฃผ์„์ด ยซ์˜์–ด๋‹คยป๋ผ๊ณ 
@@ -35,9 +35,9 @@ export declare class EmptyState extends StyledElement<ElementParts> {
35
35
  /** ๋ณด์กฐ ์„ค๋ช…. ๋น„์šฐ๋ฉด variant ๊ธฐ๋ณธ ๋ฌธ๊ตฌ. */
36
36
  description: string;
37
37
  /**
38
- * ์–ธ์–ด ํƒœ๊ทธ. ๋น„์šฐ๋ฉด `setDefaultLocale()` ๊ฐ’, ๊ทธ๊ฒƒ๋„ ์—†์œผ๋ฉด **์˜์–ด**.
38
+ * ์–ธ์–ด ํƒœ๊ทธ โ€” ์ด ์š”์†Œ๋งŒ ๋ฌธ์„œ์™€ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์“ธ ๋•Œ. ๋น„์šฐ๋ฉด `Locale` ์˜ ํ™œ์„ฑ ๋กœ์ผ€์ผ.
39
39
  * โš ๊ธฐ๋ณธ ๋ฌธ๊ตฌ๋Š” ์˜์–ด๋‹ค โ€” ์ด ํŒจํ‚ค์ง€๋Š” ๋ฒ”์šฉ ์ธต์ด๋ผ ํŠน์ • ์–ธ์–ด๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค.
40
- * ํ•œ๊ตญ์–ด๋Š” `registerLocale('ko', โ€ฆ)` ๋กœ ์†Œ๋น„์ž๊ฐ€ ๋“ฑ๋กํ•œ๋‹ค.
40
+ * ํ•œ๊ตญ์–ด๋Š” `modernAppLocale.register('ko', โ€ฆ)` ๋กœ ์†Œ๋น„์ž๊ฐ€ ๋“ฑ๋กํ•œ๋‹ค.
41
41
  */
42
42
  locale: string;
43
43
  /** ์•ก์…˜ ์Šฌ๋กฏ ๋ฐฐ์ • ์ƒํƒœ โ€” CSS `:has()` ๋กœ๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค(`internals/slotted.ts` ์ฐธ์กฐ). */
@@ -47,7 +47,7 @@ export declare class MasterDetailLayout extends StyledElement<ElementParts> {
47
47
  */
48
48
  overlayBreakpoint: number;
49
49
  /**
50
- * ์–ธ์–ด ํƒœ๊ทธ. ๋น„์šฐ๋ฉด `setDefaultLocale()` ๊ฐ’, ๊ทธ๊ฒƒ๋„ ์—†์œผ๋ฉด ์˜์–ด.
50
+ * ์–ธ์–ด ํƒœ๊ทธ โ€” ์ด ์š”์†Œ๋งŒ ๋ฌธ์„œ์™€ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์“ธ ๋•Œ. ๋น„์šฐ๋ฉด `Locale` ์˜ ํ™œ์„ฑ ๋กœ์ผ€์ผ.
51
51
  * ๋‹ซ๊ธฐ ๋ฒ„ํŠผ์˜ ์ ‘๊ทผ์„ฑ ๋ผ๋ฒจ์—๋งŒ ์“ฐ์ธ๋‹ค.
52
52
  */
53
53
  locale: string;
@@ -33,10 +33,10 @@ export declare class PageHeader extends StyledElement<ElementParts> {
33
33
  /**
34
34
  * ๋’ค๋กœ๊ฐ€๊ธฐ ๋งํฌ ๋ฌธ๊ตฌ. ๋น„์šฐ๋ฉด locale ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ๊ฐ’, ๊ทธ๊ฒƒ๋„ ์—†์œผ๋ฉด **์˜์–ด**(`Back`).
35
35
  * โš ์ด ํŒจํ‚ค์ง€๋Š” ๋ฒ”์šฉ ์ธต์ด๋ผ ํŠน์ • ์–ธ์–ด๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค โ€”
36
- * ํ•œ๊ตญ์–ด๋Š” `registerLocale('ko', { back: '๋’ค๋กœ' })` ๋กœ ์†Œ๋น„์ž๊ฐ€ ๋“ฑ๋กํ•œ๋‹ค.
36
+ * ํ•œ๊ตญ์–ด๋Š” `modernAppLocale.register('ko', { back: '๋’ค๋กœ' })` ๋กœ ์†Œ๋น„์ž๊ฐ€ ๋“ฑ๋กํ•œ๋‹ค.
37
37
  */
38
38
  backLabel: string;
39
- /** ์–ธ์–ด ํƒœ๊ทธ. ๋น„์šฐ๋ฉด `setDefaultLocale()` ๊ฐ’, ๊ทธ๊ฒƒ๋„ ์—†์œผ๋ฉด ์˜์–ด. */
39
+ /** ์–ธ์–ด ํƒœ๊ทธ โ€” ์ด ์š”์†Œ๋งŒ ๋ฌธ์„œ์™€ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์“ธ ๋•Œ. ๋น„์šฐ๋ฉด `Locale` ์˜ ํ™œ์„ฑ ๋กœ์ผ€์ผ. */
40
40
  locale: string;
41
41
  /**
42
42
  * ์Šฌ๋กฏ ๋ฐฐ์ • ์ƒํƒœ. โ˜…CSS ๋กœ๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค โ€” `<slot>` ์ž์‹ ์ด ์ž์‹์ด๋ผ `:has(*)` ๊ฐ€
package/dist/index.d.ts CHANGED
@@ -15,8 +15,8 @@ export { MasterDetailLayout } from './components/MasterDetailLayout.js';
15
15
  export { Wizard } from './components/Wizard.js';
16
16
  export type { WizardStep, WizardStepState, WizardStepChangeDetail } from './components/Wizard.js';
17
17
  export { translate } from './translate.js';
18
- export { registerLocale, setDefaultLocale, getLocaleStrings, getDefaultLocale, } from './internals/locale.js';
19
- export type { ModernAppLocaleStrings } from './internals/locale.js';
18
+ export { modernAppLocale, registerLocale, setDefaultLocale, getLocaleStrings, getDefaultLocale, } from './internals/locale.js';
19
+ export type { ModernAppLocaleStrings, ModernAppMessageKey } from './internals/locale.js';
20
20
  export { ScreenObserver } from './internals/ScreenObserver.js';
21
21
  export type { ScreenSize, ScreenObserverConfig, ScreenResizeEvent } from './internals/ScreenObserver.js';
22
22
  export { app };
package/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
1
  import { ScreenObserver as e } from "./internals/ScreenObserver.js";
2
2
  import { app as t } from "./App.js";
3
3
  import { filterSidebarItems as n } from "./layouts/filterSidebarItems.js";
4
- import { getDefaultLocale as r, getLocaleStrings as i, registerLocale as a, setDefaultLocale as o } from "./internals/locale.js";
5
- import { PageHeader as s } from "./components/PageHeader.js";
6
- import { GroupBox as c } from "./components/GroupBox.js";
7
- import { InfoSection as l } from "./components/InfoSection.js";
8
- import { InfoField as u, isBlank as d } from "./components/InfoField.js";
9
- import { EmptyState as f } from "./components/EmptyState.js";
10
- import { ActionBar as p } from "./components/ActionBar.js";
11
- import { MasterDetailLayout as m } from "./components/MasterDetailLayout.js";
12
- import { Wizard as h } from "./components/Wizard.js";
13
- import { translate as g } from "./translate.js";
4
+ import { getDefaultLocale as r, getLocaleStrings as i, modernAppLocale as a, registerLocale as o, setDefaultLocale as s } from "./internals/locale.js";
5
+ import { PageHeader as c } from "./components/PageHeader.js";
6
+ import { GroupBox as l } from "./components/GroupBox.js";
7
+ import { InfoSection as u } from "./components/InfoSection.js";
8
+ import { InfoField as d, isBlank as f } from "./components/InfoField.js";
9
+ import { EmptyState as p } from "./components/EmptyState.js";
10
+ import { ActionBar as m } from "./components/ActionBar.js";
11
+ import { MasterDetailLayout as h } from "./components/MasterDetailLayout.js";
12
+ import { Wizard as g } from "./components/Wizard.js";
13
+ import { translate as _ } from "./translate.js";
14
14
  //#region src/index.ts
15
- var _ = t;
15
+ var v = t;
16
16
  //#endregion
17
- export { p as ActionBar, f as EmptyState, c as GroupBox, u as InfoField, l as InfoSection, m as MasterDetailLayout, s as PageHeader, e as ScreenObserver, h as Wizard, t as app, _ as default, n as filterSidebarItems, r as getDefaultLocale, i as getLocaleStrings, d as isBlank, a as registerLocale, o as setDefaultLocale, g as translate };
17
+ export { m as ActionBar, p as EmptyState, l as GroupBox, d as InfoField, u as InfoSection, h as MasterDetailLayout, c as PageHeader, e as ScreenObserver, g as Wizard, t as app, v as default, n as filterSidebarItems, r as getDefaultLocale, i as getLocaleStrings, f as isBlank, a as modernAppLocale, o as registerLocale, s as setDefaultLocale, _ as translate };
@@ -1,22 +1,3 @@
1
- /**
2
- * Lightweight locale registry for modern-app chrome strings.
3
- *
4
- * Scope: library-internal chrome strings only (empty-state copy, back label).
5
- * NOT a general i18n framework โ€” the app's own content is the app's business.
6
- *
7
- * โ˜…**English is the built-in default.** This package sits in the *generic* layer
8
- * (see the three-layer split: `components` = neutral primitives, `modern-app` =
9
- * what a modern app usually provides, `enterprise` = iyulab house style).
10
- * A generic layer that ships Korean defaults excludes every non-Korean consumer โ€”
11
- * the same objection this repo raised against baking a house aesthetic into
12
- * `components`. Language excludes harder than aesthetics: an odd-looking default
13
- * is awkward, an unreadable one is unusable.
14
- *
15
- * Mirrors the registry already established in `u-widgets` โ€” one pattern, not two.
16
- *
17
- * registerLocale('ko', { back: '๋’ค๋กœ', noDataTitle: '์•„์ง ๋“ฑ๋ก๋œ ํ•ญ๋ชฉ์ด ์—†์Šต๋‹ˆ๋‹ค' });
18
- * setDefaultLocale('ko');
19
- */
20
1
  export interface ModernAppLocaleStrings {
21
2
  /** Back button label in the page header. */
22
3
  back: string;
@@ -39,18 +20,26 @@ export interface ModernAppLocaleStrings {
39
20
  wizardStepAnnouncement: (index: number, total: number, label: string) => string;
40
21
  }
41
22
  /**
42
- * Register a locale. Partial overrides are merged with the English defaults,
43
- * so a consumer can translate one string without restating the rest.
23
+ * Keys of the `modern-app` namespace. All strings โ€” `wizardStepAnnouncement` is a template with
24
+ * `{index}`, `{total}` and `{label}` placeholders (`'Step {index} of {total}: {label}'`).
25
+ */
26
+ export type ModernAppMessageKey = keyof ModernAppLocaleStrings;
27
+ /** The `modern-app` chrome-string namespace. Register translations here; pick the language with `Locale.set()`. */
28
+ export declare const modernAppLocale: import('@iyulab/components/dist/utilities/Locale.js').LocaleNamespace<keyof ModernAppLocaleStrings>;
29
+ /**
30
+ * @deprecated Register with `modernAppLocale.register(lang, strings)` and choose the language with
31
+ * `Locale.set()`. This forwards to the namespace; a function-valued `wizardStepAnnouncement` keeps
32
+ * working (the namespace form is a `{index}`/`{total}`/`{label}` template).
44
33
  */
45
34
  export declare function registerLocale(lang: string, strings: Partial<ModernAppLocaleStrings>): void;
46
- /** Set the locale used when a component does not specify one. */
35
+ /**
36
+ * @deprecated Choose the language with `Locale.set()` of `@iyulab/components` โ€” this package now
37
+ * follows it. When called, this still takes precedence over `Locale` for elements without their
38
+ * own `locale`; `setDefaultLocale(undefined)` hands the choice back to `Locale`.
39
+ */
47
40
  export declare function setDefaultLocale(lang: string | undefined): void;
48
41
  /**
49
- * Resolve strings for a language tag.
50
- *
51
- * Order: exact match (`ko-KR`) โ†’ base language (`ko`) โ†’ English.
52
- * โš The base-language step matters: consumers register `ko` but browsers report
53
- * `ko-KR`, and without it every registration would silently miss.
42
+ * Resolve every chrome string for a language tag (empty โ†’ `setDefaultLocale` โ†’ active `Locale`).
54
43
  */
55
44
  export declare function getLocaleStrings(lang?: string): ModernAppLocaleStrings;
56
45
  /** The English defaults โ€” for tests and reference. */
@@ -1,5 +1,6 @@
1
+ import { Locale as e } from "@iyulab/components/dist/utilities/Locale.js";
1
2
  //#region src/internals/locale.ts
2
- var e = {
3
+ var t = {
3
4
  back: "Back",
4
5
  noDataTitle: "Nothing here yet",
5
6
  noDataDescription: "",
@@ -10,26 +11,53 @@ var e = {
10
11
  toggleSidebar: "Toggle sidebar",
11
12
  wizardBack: "Back",
12
13
  wizardNext: "Next",
13
- wizardStepAnnouncement: (e, t, n) => `Step ${e} of ${t}: ${n}`
14
- }, t = /* @__PURE__ */ new Map(), n;
15
- function r(n, r) {
16
- t.set(n.toLowerCase(), {
17
- ...e,
18
- ...r
19
- });
14
+ wizardStepAnnouncement: "Step {index} of {total}: {label}"
15
+ }, n = e.namespace("modern-app");
16
+ n.register("en", t);
17
+ var r, i = /* @__PURE__ */ new Map(), a = "\0modern-app:announcer:";
18
+ function o(e, t) {
19
+ let { wizardStepAnnouncement: r, ...o } = t, s = { ...o };
20
+ if (r) {
21
+ let t = e.toLowerCase();
22
+ i.set(t, r), s.wizardStepAnnouncement = a + t;
23
+ }
24
+ n.register(e, s);
20
25
  }
21
- function i(e) {
22
- n = e;
26
+ function s(e) {
27
+ r = e;
23
28
  }
24
- function a(r) {
25
- let i = (r ?? n)?.toLowerCase();
26
- if (!i) return e;
27
- if (t.has(i)) return t.get(i);
28
- let a = i.split("-")[0];
29
- return a !== i && t.has(a) ? t.get(a) : e;
29
+ function c(e, t, i) {
30
+ let a = n.textIn(e || r, t, i);
31
+ return a === t ? "" : a;
30
32
  }
31
- function o() {
32
- return { ...e };
33
+ function l(e) {
34
+ let t = (t) => c(e, t);
35
+ return {
36
+ back: t("back"),
37
+ noDataTitle: t("noDataTitle"),
38
+ noDataDescription: t("noDataDescription"),
39
+ noResultsTitle: t("noResultsTitle"),
40
+ noResultsDescription: t("noResultsDescription"),
41
+ detailClose: t("detailClose"),
42
+ toggleMobileMenu: t("toggleMobileMenu"),
43
+ toggleSidebar: t("toggleSidebar"),
44
+ wizardBack: t("wizardBack"),
45
+ wizardNext: t("wizardNext"),
46
+ wizardStepAnnouncement: (t, n, r) => {
47
+ let o = c(e, "wizardStepAnnouncement", {
48
+ index: t,
49
+ total: n,
50
+ label: r
51
+ });
52
+ return o.startsWith(a) ? i.get(o.slice(22))(t, n, r) : o;
53
+ }
54
+ };
55
+ }
56
+ function u() {
57
+ return {
58
+ ...t,
59
+ wizardStepAnnouncement: (e, t, n) => `Step ${e} of ${t}: ${n}`
60
+ };
33
61
  }
34
62
  //#endregion
35
- export { o as getDefaultLocale, a as getLocaleStrings, r as registerLocale, i as setDefaultLocale };
63
+ export { u as getDefaultLocale, l as getLocaleStrings, n as modernAppLocale, o as registerLocale, s as setDefaultLocale };
@@ -9,7 +9,7 @@ export declare class SidebarLayout extends StyledElement<SidebarParts> {
9
9
  state: SidebarState;
10
10
  /** ์‚ฌ์ด๋“œ๋ฐ” ๋ ˆ์ด์•„์›ƒ ์„ค์ • */
11
11
  config?: SidebarLayoutConfig;
12
- /** ํฌ๋กฌ ๋ฌธ์ž์—ด(ํ† ๊ธ€ ๋ฒ„ํŠผ ์ ‘๊ทผ์„ฑ ๋ผ๋ฒจ ๋“ฑ) ๋กœ์ผ€์ผ โ€” `registerLocale`๋กœ ๋“ฑ๋กํ•œ ์–ธ์–ด ํƒœ๊ทธ */
12
+ /** ํฌ๋กฌ ๋ฌธ์ž์—ด(ํ† ๊ธ€ ๋ฒ„ํŠผ ์ ‘๊ทผ์„ฑ ๋ผ๋ฒจ ๋“ฑ) ๋กœ์ผ€์ผ โ€” ์ด ์š”์†Œ๋งŒ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ์“ธ ๋•Œ. ๋น„์šฐ๋ฉด `Locale` ์˜ ํ™œ์„ฑ ๋กœ์ผ€์ผ */
13
13
  locale: string;
14
14
  progressBarEl: UProgressBar;
15
15
  /** overlay ์Šฌ๋กฏ ๋ฐฐ์ • ์ƒํƒœ โ€” CSS `:has()`๋กœ๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค(`internals/slotted.ts` ์ฐธ์กฐ). */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@iyulab/modern-app",
3
3
  "description": "web-framework by iyulab based on lit-element",
4
- "version": "0.25.0",
4
+ "version": "0.26.0",
5
5
  "keywords": [
6
6
  "iyulab",
7
7
  "web-framework",
@@ -64,7 +64,7 @@
64
64
  "lit": "^3.3.3"
65
65
  },
66
66
  "peerDependencies": {
67
- "@iyulab/components": ">=1.43.0",
67
+ "@iyulab/components": ">=1.45.0",
68
68
  "@lit/react": ">=1.0.8",
69
69
  "react": ">=18.0.0"
70
70
  },
@@ -141,6 +141,30 @@ html`<p>${translate('namespace::greeting')}</p>`;
141
141
  // layout: { main: [{ type: 'link', label: translate('nav::home'), href: '/' }] }
142
142
  ```
143
143
 
144
+ ### Built-in strings (`modernAppLocale`)
145
+
146
+ The package's own strings โ€” the page header's back link, empty-state copy, the shell's toggle and
147
+ close labels, the wizard's buttons and step announcement โ€” are English by default and live in the
148
+ `modern-app` namespace of `@iyulab/components`' `Locale`. Register translations there and pick the
149
+ language once, with `Locale.set()`; the primitives and `@iyulab/flex-table` follow the same call:
150
+
151
+ ```typescript
152
+ import { Locale } from '@iyulab/components';
153
+ import { modernAppLocale } from '@iyulab/modern-app';
154
+
155
+ modernAppLocale.register('ko', {
156
+ back: '๋’ค๋กœ',
157
+ toggleSidebar: '์‚ฌ์ด๋“œ๋ฐ” ์ ‘๊ธฐ/ํŽผ์น˜๊ธฐ',
158
+ wizardStepAnnouncement: '{total}๋‹จ๊ณ„ ์ค‘ {index}๋‹จ๊ณ„: {label}',
159
+ });
160
+ Locale.set('ko');
161
+ ```
162
+
163
+ A partial table is enough โ€” untranslated keys fall back to English. An element's own `locale`
164
+ attribute overrides the active language for that element. `registerLocale`/`setDefaultLocale` still
165
+ work but are deprecated: a `setDefaultLocale()` call takes precedence over `Locale` until it is
166
+ called with `undefined`.
167
+
144
168
  ---
145
169
 
146
170
  ## Sidebar Layout
@@ -54,5 +54,6 @@ for both and a user with a filter still applied reads it as *"my data disappeare
54
54
  | `--u-space-lg` | Actions row top spacing |
55
55
  | `--u-space-sm` | Gap between actions |
56
56
 
57
- โš  Default wording is **English** โ€” register others with `registerLocale('ko', โ€ฆ)`, or pass
58
- `title`/`description` per screen.
57
+ โš  Default wording is **English** โ€” register others with `modernAppLocale.register('ko', โ€ฆ)` and
58
+ choose the language with `Locale.set()` of `@iyulab/components`, or pass `title`/`description` per
59
+ screen.
@@ -73,6 +73,10 @@ stay level:
73
73
  blank="No downtime recorded for the failures"></u-info-field>
74
74
  ```
75
75
 
76
+ `tone` colors a blank value too, so a reason that needs attention takes `tone="negative"`. Set it
77
+ conditionally (`tone=${mttr == null ? 'negative' : undefined}`) โ€” otherwise the value is toned
78
+ as well once it exists.
79
+
76
80
  ## CSS Parts
77
81
 
78
82
  | Part | Description |
@@ -59,4 +59,5 @@ screens nobody opens.
59
59
  | `--u-space-3xs` | Back-arrow-to-label spacing |
60
60
 
61
61
  โš  Built-in strings default to **English** โ€” this package is a generic layer and cannot pick a
62
- language. Register others with `registerLocale('ko', { back: '๋’ค๋กœ' })`.
62
+ language. Register others with `modernAppLocale.register('ko', { back: '๋’ค๋กœ' })` and choose the
63
+ language with `Locale.set()` of `@iyulab/components`.