@iyulab/components 1.44.1 → 1.45.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,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.45.0] - 2026-09-23
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`LocaleNamespace.textIn(locale, key, params?)` — look a string up in a given locale without
|
|
8
|
+
changing the active one.** A namespace resolved only against the active locale, and the lookup
|
|
9
|
+
chain is internal, so a package whose elements take their own `locale` attribute (one element in
|
|
10
|
+
a different language from the document) had to re-implement the chain to honor it. `textIn`
|
|
11
|
+
walks the same chain as `text()`; an empty `locale` means the active one. `text` and `textIn`
|
|
12
|
+
also keep working when taken off the handle (`const { text } = ns`).
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **A region-less language tag now reaches the shipped regional table.** Chinese and Portuguese
|
|
17
|
+
ship only as `zh-CN`, `zh-TW` and `pt-BR`, and the lookup chain only shortened a tag (`ko-KR` →
|
|
18
|
+
`ko`) — so a page with `<html lang="zh">` or `lang="pt"`, a common and valid choice, rendered
|
|
19
|
+
every built-in string (clear buttons, steppers, validation messages) in English. The chain now
|
|
20
|
+
shortens a tag one subtag at a time and then falls to the language's default regional table:
|
|
21
|
+
`zh` → `zh-CN`, `pt` → `pt-BR`, and Traditional Chinese tags (`zh-Hant`, `zh-HK`, `zh-MO`) →
|
|
22
|
+
`zh-TW` rather than the Simplified default. A table you register for the region-less tag still
|
|
23
|
+
comes first. `Locale.namespace()` shares the chain, so packages that register their own strings
|
|
24
|
+
get the same resolution.
|
|
25
|
+
|
|
3
26
|
## [1.44.1] - 2026-09-23
|
|
4
27
|
|
|
5
28
|
### Fixed
|
package/README.md
CHANGED
|
@@ -186,8 +186,9 @@ t.text('empty'); // 활성 로케일 기준
|
|
|
186
186
|
t.text('greet', { who: 'Ann' }); // {name} 치환
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
-
- 조회 사슬은 검증 메시지와 같습니다: **정확 일치 →
|
|
189
|
+
- 조회 사슬은 검증 메시지와 같습니다: **정확 일치 → 접두(`zh-Hant-HK` → `zh-Hant` → `zh`) → 그 언어의 기본 지역형(`zh` → `zh-CN` · `zh-Hant`/`zh-HK` → `zh-TW` · `pt` → `pt-BR`) → `en`**.
|
|
190
190
|
- 같은 이름의 네임스페이스는 **같은 저장소**를 가리킵니다(모듈 어디서 만들어도 됩니다).
|
|
191
|
+
- 요소 하나가 문서와 다른 언어를 쓴다면(인스턴스별 `locale` 속성) `t.textIn(locale, 'empty')` 로 찾습니다 — 사슬은 같고 활성 로케일은 바꾸지 않습니다. `locale` 이 비어 있으면 활성 로케일입니다.
|
|
191
192
|
- 사슬에 없는 키는 **키 자체**를 돌려줍니다 — 조용히 빈 문자열이 되지 않습니다.
|
|
192
193
|
- `Locale.set()` 하나로 검증 메시지와 네임스페이스가 함께 전환됩니다.
|
|
193
194
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 범위: 라이브러리가 스스로 생성하는 chrome 문자열(검증 메시지 등)만 대상.
|
|
5
5
|
* 일반 i18n 프레임워크가 아니다. 앱 콘텐츠 번역은 consumer 의 i18n 계층이 담당한다.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* `SupportedLocale` 의 14개 언어가 빌드 시점에 내장된다 (src/assets/locales/*.json).
|
|
8
8
|
* 그 외 언어는 register()로 테이블 단위 등록/오버라이드한다.
|
|
9
9
|
*/
|
|
10
10
|
/** 라이브러리가 기본 제공하는 로케일. */
|
|
@@ -34,10 +34,16 @@ export interface LocaleNamespace<K extends string = string> {
|
|
|
34
34
|
register(locale: LocaleTag, table: Partial<Record<K, string>>): void;
|
|
35
35
|
/**
|
|
36
36
|
* 활성 로케일 기준으로 문자열을 찾는다.
|
|
37
|
-
* 사슬(정확 일치 →
|
|
37
|
+
* 사슬(정확 일치 → 접두 → 기본 지역형 → en)에 없으면 **키 자체를 돌려준다** — 조용히 빈 문자열이
|
|
38
38
|
* 되는 것보다 화면에 드러나는 편이 낫다.
|
|
39
39
|
*/
|
|
40
40
|
text(key: K, params?: Record<string, string | number>): string;
|
|
41
|
+
/**
|
|
42
|
+
* `text()` 와 같되 **주어진 로케일**로 찾는다 — 활성 로케일은 바꾸지 않는다.
|
|
43
|
+
* 요소 하나가 문서와 다른 언어를 쓰는 자리(인스턴스별 `locale` 속성)를 위한 것이다.
|
|
44
|
+
* 사슬은 `text()` 와 같고, `locale` 이 비어 있으면(`undefined`·`''`) 활성 로케일을 쓴다.
|
|
45
|
+
*/
|
|
46
|
+
textIn(locale: LocaleTag | undefined, key: K, params?: Record<string, string | number>): string;
|
|
41
47
|
}
|
|
42
48
|
/**
|
|
43
49
|
* 검증 메시지 로케일을 관리하는 정적 유틸리티입니다.
|
package/dist/utilities/Locale.js
CHANGED
|
@@ -49,15 +49,38 @@ function detectLocale() {
|
|
|
49
49
|
return "en";
|
|
50
50
|
}
|
|
51
51
|
var active = detectLocale();
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* 내장 표가 **지역형으로만** 있는 언어의 기본 지역형 — 키는 태그의 접두(소문자).
|
|
54
|
+
*
|
|
55
|
+
* ⚠`lang="zh"`·`"pt"` 처럼 지역 없는 태그는 흔하고 정당하다(BCP 47). 사슬이 접두를 줄여 가기만
|
|
56
|
+
* 하면 그 태그는 `zh-CN`·`pt-BR` 표에 **닿지 못하고** 영어로 떨어진다.
|
|
57
|
+
* ⚠«같은 base 의 첫 번째 표» 로 고르지 않고 **명시한다** — 중국어는 표기 체계가 둘이라 고르는
|
|
58
|
+
* 순서에 따라 번체 사용자가 간체를 받는다. 번체 쪽 태그(`zh-Hant`·`zh-HK`·`zh-MO`)는 `zh-TW` 로,
|
|
59
|
+
* 나머지 중국어는 `zh-CN` 으로. 사슬은 **가장 구체적인 접두부터** 이 표를 찾는다.
|
|
60
|
+
*/
|
|
61
|
+
var REGIONAL_DEFAULTS = {
|
|
62
|
+
"zh-hant": "zh-tw",
|
|
63
|
+
"zh-hk": "zh-tw",
|
|
64
|
+
"zh-mo": "zh-tw",
|
|
65
|
+
zh: "zh-cn",
|
|
66
|
+
pt: "pt-br"
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* 조회 사슬 — 정확 일치 → 접두를 줄여 가며(RFC 4647 lookup: `zh-hant-hk → zh-hant → zh`) →
|
|
70
|
+
* 그 언어의 기본 지역형(`REGIONAL_DEFAULTS`) → `en`.
|
|
71
|
+
*
|
|
72
|
+
* 앱이 `register('pt', …)` 로 지역 없는 표를 직접 등록하면 그것이 기본 지역형보다 먼저 온다.
|
|
73
|
+
*/
|
|
53
74
|
function chainOf(locale) {
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
75
|
+
const subtags = locale.toLowerCase().split("-");
|
|
76
|
+
const prefixes = subtags.map((_, i) => subtags.slice(0, subtags.length - i).join("-"));
|
|
77
|
+
const regional = prefixes.find((p) => p in REGIONAL_DEFAULTS);
|
|
78
|
+
const chain = regional ? [
|
|
79
|
+
...prefixes,
|
|
80
|
+
REGIONAL_DEFAULTS[regional],
|
|
59
81
|
"en"
|
|
60
|
-
];
|
|
82
|
+
] : [...prefixes, "en"];
|
|
83
|
+
return [...new Set(chain)];
|
|
61
84
|
}
|
|
62
85
|
/** 템플릿의 `{name}` 자리를 치환한다. 값이 없는 자리는 그대로 남긴다(디버깅 단서). */
|
|
63
86
|
function interpolate(template, params) {
|
|
@@ -114,6 +137,14 @@ var Locale = class {
|
|
|
114
137
|
* @param name 네임스페이스 이름. 패키지·컴포넌트 단위를 권장합니다(예: `'u-data-view'`).
|
|
115
138
|
*/
|
|
116
139
|
static namespace(name) {
|
|
140
|
+
const textIn = (locale, key, params) => {
|
|
141
|
+
const byLocale = namespaces.get(name);
|
|
142
|
+
for (const tag of chainOf(locale || active)) {
|
|
143
|
+
const value = byLocale?.get(tag)?.[key];
|
|
144
|
+
if (value) return interpolate(value, params);
|
|
145
|
+
}
|
|
146
|
+
return key;
|
|
147
|
+
};
|
|
117
148
|
return {
|
|
118
149
|
name,
|
|
119
150
|
register(locale, table) {
|
|
@@ -125,14 +156,8 @@ var Locale = class {
|
|
|
125
156
|
});
|
|
126
157
|
namespaces.set(name, byLocale);
|
|
127
158
|
},
|
|
128
|
-
text(key, params)
|
|
129
|
-
|
|
130
|
-
for (const tag of chainOf(active)) {
|
|
131
|
-
const value = byLocale?.get(tag)?.[key];
|
|
132
|
-
if (value) return interpolate(value, params);
|
|
133
|
-
}
|
|
134
|
-
return key;
|
|
135
|
-
}
|
|
159
|
+
text: (key, params) => textIn(void 0, key, params),
|
|
160
|
+
textIn
|
|
136
161
|
};
|
|
137
162
|
}
|
|
138
163
|
};
|
package/package.json
CHANGED
|
@@ -16,6 +16,21 @@ declaration of the document's language and is what assistive technology uses to
|
|
|
16
16
|
pronunciation rules (WCAG 3.1.1 / 3.1.2); the browser language is the user-preference
|
|
17
17
|
fallback for when no such declaration exists. Call `Locale.set()` to override either.
|
|
18
18
|
|
|
19
|
+
## Resolution
|
|
20
|
+
|
|
21
|
+
A message is looked up along a chain, first match wins:
|
|
22
|
+
|
|
23
|
+
1. the exact tag (case-insensitive);
|
|
24
|
+
2. the tag with trailing subtags removed, one at a time (`zh-Hant-HK` → `zh-Hant` → `zh`);
|
|
25
|
+
3. the language's default regional table, for languages shipped only in regional form —
|
|
26
|
+
`zh` → `zh-CN`, `zh-Hant` / `zh-HK` / `zh-MO` → `zh-TW`, `pt` → `pt-BR`;
|
|
27
|
+
4. `en`.
|
|
28
|
+
|
|
29
|
+
So `<html lang="zh">` or `lang="pt"` gets the shipped Chinese or Portuguese strings, and a
|
|
30
|
+
Traditional Chinese tag gets `zh-TW` rather than the Simplified default. A table you register for
|
|
31
|
+
the region-less tag (`Locale.register('pt', …)`) comes before step 3. `Locale.namespace()` uses the
|
|
32
|
+
same chain.
|
|
33
|
+
|
|
19
34
|
## API
|
|
20
35
|
|
|
21
36
|
| Method | Description |
|
|
@@ -24,6 +39,26 @@ fallback for when no such declaration exists. Call `Locale.set()` to override ei
|
|
|
24
39
|
| `Locale.get()` | Get active locale |
|
|
25
40
|
| `Locale.register(locale, table)` | Register/override locale messages (partial merge supported) |
|
|
26
41
|
| `Locale.getValue(key, params?)` | Resolve a localized message for current locale |
|
|
42
|
+
| `Locale.namespace(name)` | A string table for a package or app area, keyed by its own union — returns a handle (below) |
|
|
43
|
+
|
|
44
|
+
### Namespaces
|
|
45
|
+
|
|
46
|
+
`Locale.getValue` covers the library's own message keys. A package built on top keeps its own
|
|
47
|
+
strings in a namespace and follows the same active locale and chain:
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
const t = Locale.namespace<'empty' | 'greet'>('my-package');
|
|
51
|
+
t.register('en', { empty: 'No data', greet: 'Hello, {who}' });
|
|
52
|
+
t.register('ko', { empty: '데이터가 없습니다' }); // partial tables merge
|
|
53
|
+
|
|
54
|
+
t.text('empty'); // active locale
|
|
55
|
+
t.text('greet', { who: 'Ann' }); // {name} substitution
|
|
56
|
+
t.textIn(el.locale, 'empty'); // a given locale (e.g. an element's own `locale`);
|
|
57
|
+
// empty → active locale. Does not change the active one.
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
A key missing from every table in the chain returns the key itself, so a gap shows on screen
|
|
61
|
+
instead of rendering as an empty string.
|
|
27
62
|
|
|
28
63
|
## Example
|
|
29
64
|
|