@pactor-app/i18n 0.0.0-stage → 1.55.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/LICENSE +21 -0
- package/README.md +118 -2
- package/dist/chunk-3YCHXWF6.js +1032 -0
- package/dist/index.cjs +1075 -0
- package/dist/index.d.cts +258 -0
- package/dist/index.d.ts +258 -0
- package/dist/index.js +40 -0
- package/dist/node.cjs +1354 -0
- package/dist/node.d.cts +99 -0
- package/dist/node.d.ts +99 -0
- package/dist/node.js +315 -0
- package/package.json +75 -3
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { MessageBundleSet, PageDsl, I18nKeyRef, I18nInlineMessages } from '@pactor-app/core';
|
|
2
|
+
|
|
3
|
+
/** i18n 包统一错误码 */
|
|
4
|
+
type I18nErrorCode = 'INVALID_LOCALE_CONFIG' | 'INVALID_LOCALE' | 'UNSUPPORTED_LOCALE' | 'LOCALE_CONFLICT' | 'DUPLICATE_LOCALE_PARAM' | 'MANIFEST_INVALID' | 'MANIFEST_MISMATCH' | 'NAMESPACE_NOT_FOUND' | 'MESSAGE_BUNDLE_INVALID' | 'MESSAGE_PROTOCOL_ERROR' | 'MESSAGE_FETCH_FAILED' | 'INVALID_FIELD_PATH' | 'UNREGISTERED_I18N_FIELD' | 'I18N_DESCRIPTOR_INVALID' | 'BINDING_INVALID' | 'BINDING_CONFLICT' | 'UNSAFE_MESSAGE' | 'PAGE_LOAD_FAILED' | 'PAGE_YAML_INVALID' | 'PAGE_DSL_INVALID';
|
|
5
|
+
/** 携带可识别 code 的 i18n 错误 */
|
|
6
|
+
declare class I18nError extends Error {
|
|
7
|
+
readonly code: I18nErrorCode;
|
|
8
|
+
readonly details?: Record<string, unknown> | undefined;
|
|
9
|
+
constructor(code: I18nErrorCode, message: string, details?: Record<string, unknown> | undefined);
|
|
10
|
+
}
|
|
11
|
+
/** 判断错误是否为 I18nError(可选按 code 过滤) */
|
|
12
|
+
declare function isI18nError(error: unknown, code?: I18nErrorCode): error is I18nError;
|
|
13
|
+
|
|
14
|
+
/** 语言来源 */
|
|
15
|
+
type LocaleSource = 'url-path' | 'url-query' | 'cookie' | 'accept-language' | 'application-default';
|
|
16
|
+
/** resolveRequestLocale 输入:宿主把请求信息适配为普通对象 */
|
|
17
|
+
interface ResolveLocaleInput {
|
|
18
|
+
/** 路径中的语言段,如 /en-US/users 提取出的 'en-US' */
|
|
19
|
+
pathLocale?: string;
|
|
20
|
+
/** 查询参数 locale;数组表示重复参数 */
|
|
21
|
+
queryLocale?: string | string[];
|
|
22
|
+
/** 已解析出的 locale Cookie 值 */
|
|
23
|
+
cookieLocale?: string;
|
|
24
|
+
/** Accept-Language 请求头原文 */
|
|
25
|
+
acceptLanguage?: string;
|
|
26
|
+
}
|
|
27
|
+
/** 应用语言配置 */
|
|
28
|
+
interface LocaleResolverConfig {
|
|
29
|
+
supportedLocales: string[];
|
|
30
|
+
defaultLocale: string;
|
|
31
|
+
/** 无显式语言时的默认策略,缺省 'system' */
|
|
32
|
+
defaultStrategy?: 'system' | 'application';
|
|
33
|
+
/** 显式配置的别名映射,如 { en: 'en-US' } */
|
|
34
|
+
aliases?: Record<string, string>;
|
|
35
|
+
/** 语言级回退映射,如 { 'fr-CA': ['fr'] },仅用于 Accept-Language 协商 */
|
|
36
|
+
fallbackLocales?: Record<string, string[]>;
|
|
37
|
+
}
|
|
38
|
+
/** 解析结果:唯一有效 locale 及来源 */
|
|
39
|
+
interface ResolvedRequestLocale {
|
|
40
|
+
locale: string;
|
|
41
|
+
source: LocaleSource;
|
|
42
|
+
explicit: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** Accept-Language 条目(已按 q 降序、同权重按出现顺序排序) */
|
|
45
|
+
interface AcceptLanguageEntry {
|
|
46
|
+
tag: string;
|
|
47
|
+
q: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 规范化语言标识:语言小写、地区大写、文字系统首字母大写,`_` 归一为 `-`。
|
|
51
|
+
* 非法格式返回 undefined。
|
|
52
|
+
*/
|
|
53
|
+
declare function normalizeLocaleTag(value: string): string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* 解析 Accept-Language 请求头。
|
|
56
|
+
* 忽略 q=0、非法语言项与无效权重;结果按 q 降序、同权重按出现顺序排列。
|
|
57
|
+
*/
|
|
58
|
+
declare function parseAcceptLanguage(header: string | undefined): AcceptLanguageEntry[];
|
|
59
|
+
/**
|
|
60
|
+
* 解析请求有效语言。优先级:URL path/query > locale Cookie >
|
|
61
|
+
* Accept-Language(仅 system 策略)> 应用 defaultLocale。
|
|
62
|
+
*
|
|
63
|
+
* 显式值非法 / 不支持 / 冲突时抛 I18nError(INVALID_LOCALE /
|
|
64
|
+
* UNSUPPORTED_LOCALE / LOCALE_CONFLICT / DUPLICATE_LOCALE_PARAM),
|
|
65
|
+
* 不静默回退;Cookie 失效则忽略并继续解析链。
|
|
66
|
+
*/
|
|
67
|
+
declare function resolveRequestLocale(input: ResolveLocaleInput, config: LocaleResolverConfig): ResolvedRequestLocale;
|
|
68
|
+
|
|
69
|
+
/** MessageProvider.load 输入(设计 6.0.3 统一契约) */
|
|
70
|
+
interface LoadMessagesInput {
|
|
71
|
+
appId: string;
|
|
72
|
+
/** 来自服务端可信上下文,不接受浏览器任意指定 */
|
|
73
|
+
tenantId?: string;
|
|
74
|
+
locale: string;
|
|
75
|
+
namespaces: string[];
|
|
76
|
+
release: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 渲染服务统一语言包 Provider 契约。
|
|
80
|
+
* YamlMessageProvider 与 ApiMessageProvider 输出完全相同的 MessageBundleSet,
|
|
81
|
+
* 消费方(如 DslLocalizer)只依赖此接口。
|
|
82
|
+
*/
|
|
83
|
+
interface MessageProvider {
|
|
84
|
+
load(input: LoadMessagesInput): Promise<MessageBundleSet>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 浏览器/Node 中立的 fetch 响应形态 */
|
|
88
|
+
interface FetchLikeResponse {
|
|
89
|
+
status: number;
|
|
90
|
+
headers: {
|
|
91
|
+
get(name: string): string | null;
|
|
92
|
+
};
|
|
93
|
+
text(): Promise<string>;
|
|
94
|
+
}
|
|
95
|
+
/** 注入的 fetch 风格函数 */
|
|
96
|
+
type FetchLike = (url: string, init?: {
|
|
97
|
+
headers?: Record<string, string>;
|
|
98
|
+
}) => Promise<FetchLikeResponse>;
|
|
99
|
+
interface ApiMessageProviderOptions {
|
|
100
|
+
/** 语言包 API 地址,来自服务端应用配置,不接受浏览器任意指定 */
|
|
101
|
+
endpoint: string;
|
|
102
|
+
fetch: FetchLike;
|
|
103
|
+
/** 服务端凭据等附加请求头(如 Authorization) */
|
|
104
|
+
headers?: Record<string, string>;
|
|
105
|
+
}
|
|
106
|
+
/** load 扩展输入:可显式传入缓存的 ETag */
|
|
107
|
+
interface ApiLoadInput extends LoadMessagesInput {
|
|
108
|
+
etag?: string;
|
|
109
|
+
}
|
|
110
|
+
/** 携带缓存信息的加载结果 */
|
|
111
|
+
interface ApiLoadResult {
|
|
112
|
+
bundleSet: MessageBundleSet;
|
|
113
|
+
etag?: string;
|
|
114
|
+
/** 304 复用已校验缓存包时为 true */
|
|
115
|
+
notModified: boolean;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 语言包 API Provider(设计 6.0.3 / 6.1)。
|
|
119
|
+
*
|
|
120
|
+
* 校验 HTTP 状态与 Content-Type(必须 application/json)、解析 JSON、
|
|
121
|
+
* 校验 envelope 协议字段与 format;返回 YAML 或内嵌 YAML 字符串按
|
|
122
|
+
* MESSAGE_PROTOCOL_ERROR 处理,不切换解析方式。
|
|
123
|
+
*
|
|
124
|
+
* ETag / If-None-Match:provider 内部按缓存键(appId/tenant/locale/
|
|
125
|
+
* namespaces/release)记录最近校验通过的包及其 ETag;304 时复用该缓存,
|
|
126
|
+
* 结果携带 notModified 标记。也可通过 load 输入的 etag 显式指定。
|
|
127
|
+
*/
|
|
128
|
+
declare class ApiMessageProvider implements MessageProvider {
|
|
129
|
+
private readonly options;
|
|
130
|
+
private readonly cache;
|
|
131
|
+
constructor(options: ApiMessageProviderOptions);
|
|
132
|
+
/** MessageProvider 契约实现 */
|
|
133
|
+
load(input: ApiLoadInput): Promise<MessageBundleSet>;
|
|
134
|
+
/** 加载并返回缓存信息(ETag / notModified) */
|
|
135
|
+
loadWithCacheInfo(input: ApiLoadInput): Promise<ApiLoadResult>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
declare function isValidMessageKey(key: string): boolean;
|
|
139
|
+
/**
|
|
140
|
+
* 校验扁平词条表:顶层必须为普通对象,键名合法,值全部为字符串。
|
|
141
|
+
* 不合法时抛出指定 code 的 I18nError。
|
|
142
|
+
*/
|
|
143
|
+
declare function assertMessages(value: unknown, context: string, code: I18nErrorCode): Record<string, string>;
|
|
144
|
+
/** namespace 间完整 key 冲突检查(结果与 namespace 遍历顺序无关) */
|
|
145
|
+
declare function assertNoCrossNamespaceKeyConflicts(bundles: Record<string, Record<string, string>>, code: I18nErrorCode): void;
|
|
146
|
+
interface EnvelopeExpectation {
|
|
147
|
+
appId: string;
|
|
148
|
+
locale: string;
|
|
149
|
+
release: string;
|
|
150
|
+
namespaces: readonly string[];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 校验语言包 API 的 JSON envelope(设计 6.1)。
|
|
154
|
+
* 结构/协议字段问题抛 MESSAGE_PROTOCOL_ERROR;缺失请求的 namespace 抛 NAMESPACE_NOT_FOUND。
|
|
155
|
+
*/
|
|
156
|
+
declare function validateBundleSetEnvelope(data: unknown, expected: EnvelopeExpectation): MessageBundleSet;
|
|
157
|
+
|
|
158
|
+
declare class TranslatableFieldRegistry {
|
|
159
|
+
private readonly componentFields;
|
|
160
|
+
private readonly actionFields;
|
|
161
|
+
/** 注册组件 type 的可翻译字段路径(可重复调用,累积合并) */
|
|
162
|
+
register(componentType: string, fields: string | readonly string[]): this;
|
|
163
|
+
/** 注册动作名的可翻译参数字段路径(如 message 动作的 `params.text`) */
|
|
164
|
+
registerAction(actionName: string, fields: string | readonly string[]): this;
|
|
165
|
+
/**
|
|
166
|
+
* 判断组件字段是否已注册。`canonicalPath` 为规范化路径
|
|
167
|
+
* (数组下标段写作 `[*]`,如 `props.columns[*].title`)。
|
|
168
|
+
*/
|
|
169
|
+
isTranslatable(componentType: string | undefined, canonicalPath: string): boolean;
|
|
170
|
+
/** 判断动作参数字段是否已注册 */
|
|
171
|
+
isTranslatableActionField(actionName: string, canonicalPath: string): boolean;
|
|
172
|
+
/** 已注册组件 type 列表(诊断/调试用) */
|
|
173
|
+
registeredComponents(): string[];
|
|
174
|
+
/** 已注册动作名列表(诊断/调试用) */
|
|
175
|
+
registeredActions(): string[];
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 内置注册表(设计 4.4 常用展示字段):
|
|
179
|
+
* Button/Text/Input/Table 列/Select 选项,以及 message / confirm 动作参数。
|
|
180
|
+
*/
|
|
181
|
+
declare function createDefaultTranslatableFieldRegistry(): TranslatableFieldRegistry;
|
|
182
|
+
/**
|
|
183
|
+
* 共享默认注册表(惰性创建)。请勿原地修改返回的实例;
|
|
184
|
+
* 需要自定义时通过 `createDefaultTranslatableFieldRegistry()` 或
|
|
185
|
+
* `new TranslatableFieldRegistry()` 创建独立副本。
|
|
186
|
+
*/
|
|
187
|
+
declare function getDefaultTranslatableFieldRegistry(): TranslatableFieldRegistry;
|
|
188
|
+
|
|
189
|
+
/** 转义单个 JSON Pointer 段(`~` → `~0`、`/` → `~1`) */
|
|
190
|
+
declare function escapeJsonPointerSegment(segment: string): string;
|
|
191
|
+
/**
|
|
192
|
+
* 解析 JSON Pointer(RFC 6901)为段数组。
|
|
193
|
+
* 空串返回 `[]`(指整个文档);`~0`/`~1` 之外的转义、非 `/` 开头均抛 BINDING_INVALID。
|
|
194
|
+
*/
|
|
195
|
+
declare function parseJsonPointer(pointer: string): string[];
|
|
196
|
+
/** bindings 定位结果:父容器、末段键与当前值 */
|
|
197
|
+
interface ResolvedJsonPointer {
|
|
198
|
+
parent: Record<string, unknown> | unknown[];
|
|
199
|
+
key: string | number;
|
|
200
|
+
value: unknown;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 按段数组定位目标字段。空指针(指整个文档)、中间段或末段不存在、
|
|
204
|
+
* 数组下标非法均抛 BINDING_INVALID。
|
|
205
|
+
*/
|
|
206
|
+
declare function resolveJsonPointer(root: unknown, segments: readonly string[], pointer: string): ResolvedJsonPointer;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* DslLocalizer(设计第 4、6、7、8 节,缺口 G03/G04/G17)。
|
|
210
|
+
*
|
|
211
|
+
* 纯转换入口:语言包作为参数显式传入,不在遍历组件时自行请求。
|
|
212
|
+
* 统一处理三种声明方式(`$i18n.messages`、`$i18n.key`、页面 `i18n.bindings`),
|
|
213
|
+
* 返回已本地化的新对象(不修改输入);编译后移除作者态 `i18n` 字段。
|
|
214
|
+
*/
|
|
215
|
+
/** 翻译描述(bindings 值与 `$i18n` 内层共用形态) */
|
|
216
|
+
type TranslationDescriptor = I18nKeyRef | I18nInlineMessages;
|
|
217
|
+
/** 页面作者态 i18n 字段(设计 4.2) */
|
|
218
|
+
interface AuthorPageI18n {
|
|
219
|
+
namespaces?: string[];
|
|
220
|
+
bindings?: Record<string, TranslationDescriptor>;
|
|
221
|
+
}
|
|
222
|
+
/** 作者态 Page DSL(PageDsl + 顶层 i18n 字段) */
|
|
223
|
+
type AuthorPageDsl = PageDsl & {
|
|
224
|
+
i18n?: AuthorPageI18n;
|
|
225
|
+
};
|
|
226
|
+
/** 显式传入的语言包链:current 为当前 locale,fallbacks 有序(显式语言级回退 → defaultLocale) */
|
|
227
|
+
interface LanguageBundles {
|
|
228
|
+
current: MessageBundleSet;
|
|
229
|
+
fallbacks?: MessageBundleSet[];
|
|
230
|
+
}
|
|
231
|
+
/** 词条未在当前 locale 命中时的实际命中方式 */
|
|
232
|
+
type MissingResolution = 'fallback-locale' | 'default-locale' | 'fallback' | 'implicit-fallback' | 'key' | 'missing-text';
|
|
233
|
+
interface LocalizeDiagnostic {
|
|
234
|
+
type: 'missing-translation' | 'missing-param';
|
|
235
|
+
/** 展示用文档路径(JSON Pointer 形态,数组为真实下标) */
|
|
236
|
+
path: string;
|
|
237
|
+
locale: string;
|
|
238
|
+
key?: string;
|
|
239
|
+
param?: string;
|
|
240
|
+
resolution?: MissingResolution | 'placeholder';
|
|
241
|
+
}
|
|
242
|
+
interface LocalizePageDslInput {
|
|
243
|
+
page: AuthorPageDsl;
|
|
244
|
+
locale: string;
|
|
245
|
+
defaultLocale: string;
|
|
246
|
+
languageBundles: LanguageBundles;
|
|
247
|
+
registry?: TranslatableFieldRegistry;
|
|
248
|
+
onDiagnostic?: (diagnostic: LocalizeDiagnostic) => void;
|
|
249
|
+
}
|
|
250
|
+
/** 内联描述无 key 且所有回退失败时的统一缺失文案 */
|
|
251
|
+
declare const MISSING_TRANSLATION_TEXT = "[missing translation]";
|
|
252
|
+
/**
|
|
253
|
+
* 纯转换入口(设计第 6 节签名)。返回已本地化的新 Page DSL 对象,
|
|
254
|
+
* 不修改输入(page / languageBundles 均不被改写);作者态 `i18n` 字段被移除。
|
|
255
|
+
*/
|
|
256
|
+
declare function localizePageDsl(input: LocalizePageDslInput): PageDsl;
|
|
257
|
+
|
|
258
|
+
export { type AcceptLanguageEntry, type ApiLoadInput, type ApiLoadResult, ApiMessageProvider, type ApiMessageProviderOptions, type AuthorPageDsl, type AuthorPageI18n, type EnvelopeExpectation, type FetchLike, type FetchLikeResponse, I18nError, type I18nErrorCode, type LanguageBundles, type LoadMessagesInput, type LocaleResolverConfig, type LocaleSource, type LocalizeDiagnostic, type LocalizePageDslInput, MISSING_TRANSLATION_TEXT, type MessageProvider, type MissingResolution, type ResolveLocaleInput, type ResolvedJsonPointer, type ResolvedRequestLocale, TranslatableFieldRegistry, type TranslationDescriptor, assertMessages, assertNoCrossNamespaceKeyConflicts, createDefaultTranslatableFieldRegistry, escapeJsonPointerSegment, getDefaultTranslatableFieldRegistry, isI18nError, isValidMessageKey, localizePageDsl, normalizeLocaleTag, parseAcceptLanguage, parseJsonPointer, resolveJsonPointer, resolveRequestLocale, validateBundleSetEnvelope };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { MessageBundleSet, PageDsl, I18nKeyRef, I18nInlineMessages } from '@pactor-app/core';
|
|
2
|
+
|
|
3
|
+
/** i18n 包统一错误码 */
|
|
4
|
+
type I18nErrorCode = 'INVALID_LOCALE_CONFIG' | 'INVALID_LOCALE' | 'UNSUPPORTED_LOCALE' | 'LOCALE_CONFLICT' | 'DUPLICATE_LOCALE_PARAM' | 'MANIFEST_INVALID' | 'MANIFEST_MISMATCH' | 'NAMESPACE_NOT_FOUND' | 'MESSAGE_BUNDLE_INVALID' | 'MESSAGE_PROTOCOL_ERROR' | 'MESSAGE_FETCH_FAILED' | 'INVALID_FIELD_PATH' | 'UNREGISTERED_I18N_FIELD' | 'I18N_DESCRIPTOR_INVALID' | 'BINDING_INVALID' | 'BINDING_CONFLICT' | 'UNSAFE_MESSAGE' | 'PAGE_LOAD_FAILED' | 'PAGE_YAML_INVALID' | 'PAGE_DSL_INVALID';
|
|
5
|
+
/** 携带可识别 code 的 i18n 错误 */
|
|
6
|
+
declare class I18nError extends Error {
|
|
7
|
+
readonly code: I18nErrorCode;
|
|
8
|
+
readonly details?: Record<string, unknown> | undefined;
|
|
9
|
+
constructor(code: I18nErrorCode, message: string, details?: Record<string, unknown> | undefined);
|
|
10
|
+
}
|
|
11
|
+
/** 判断错误是否为 I18nError(可选按 code 过滤) */
|
|
12
|
+
declare function isI18nError(error: unknown, code?: I18nErrorCode): error is I18nError;
|
|
13
|
+
|
|
14
|
+
/** 语言来源 */
|
|
15
|
+
type LocaleSource = 'url-path' | 'url-query' | 'cookie' | 'accept-language' | 'application-default';
|
|
16
|
+
/** resolveRequestLocale 输入:宿主把请求信息适配为普通对象 */
|
|
17
|
+
interface ResolveLocaleInput {
|
|
18
|
+
/** 路径中的语言段,如 /en-US/users 提取出的 'en-US' */
|
|
19
|
+
pathLocale?: string;
|
|
20
|
+
/** 查询参数 locale;数组表示重复参数 */
|
|
21
|
+
queryLocale?: string | string[];
|
|
22
|
+
/** 已解析出的 locale Cookie 值 */
|
|
23
|
+
cookieLocale?: string;
|
|
24
|
+
/** Accept-Language 请求头原文 */
|
|
25
|
+
acceptLanguage?: string;
|
|
26
|
+
}
|
|
27
|
+
/** 应用语言配置 */
|
|
28
|
+
interface LocaleResolverConfig {
|
|
29
|
+
supportedLocales: string[];
|
|
30
|
+
defaultLocale: string;
|
|
31
|
+
/** 无显式语言时的默认策略,缺省 'system' */
|
|
32
|
+
defaultStrategy?: 'system' | 'application';
|
|
33
|
+
/** 显式配置的别名映射,如 { en: 'en-US' } */
|
|
34
|
+
aliases?: Record<string, string>;
|
|
35
|
+
/** 语言级回退映射,如 { 'fr-CA': ['fr'] },仅用于 Accept-Language 协商 */
|
|
36
|
+
fallbackLocales?: Record<string, string[]>;
|
|
37
|
+
}
|
|
38
|
+
/** 解析结果:唯一有效 locale 及来源 */
|
|
39
|
+
interface ResolvedRequestLocale {
|
|
40
|
+
locale: string;
|
|
41
|
+
source: LocaleSource;
|
|
42
|
+
explicit: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** Accept-Language 条目(已按 q 降序、同权重按出现顺序排序) */
|
|
45
|
+
interface AcceptLanguageEntry {
|
|
46
|
+
tag: string;
|
|
47
|
+
q: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 规范化语言标识:语言小写、地区大写、文字系统首字母大写,`_` 归一为 `-`。
|
|
51
|
+
* 非法格式返回 undefined。
|
|
52
|
+
*/
|
|
53
|
+
declare function normalizeLocaleTag(value: string): string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* 解析 Accept-Language 请求头。
|
|
56
|
+
* 忽略 q=0、非法语言项与无效权重;结果按 q 降序、同权重按出现顺序排列。
|
|
57
|
+
*/
|
|
58
|
+
declare function parseAcceptLanguage(header: string | undefined): AcceptLanguageEntry[];
|
|
59
|
+
/**
|
|
60
|
+
* 解析请求有效语言。优先级:URL path/query > locale Cookie >
|
|
61
|
+
* Accept-Language(仅 system 策略)> 应用 defaultLocale。
|
|
62
|
+
*
|
|
63
|
+
* 显式值非法 / 不支持 / 冲突时抛 I18nError(INVALID_LOCALE /
|
|
64
|
+
* UNSUPPORTED_LOCALE / LOCALE_CONFLICT / DUPLICATE_LOCALE_PARAM),
|
|
65
|
+
* 不静默回退;Cookie 失效则忽略并继续解析链。
|
|
66
|
+
*/
|
|
67
|
+
declare function resolveRequestLocale(input: ResolveLocaleInput, config: LocaleResolverConfig): ResolvedRequestLocale;
|
|
68
|
+
|
|
69
|
+
/** MessageProvider.load 输入(设计 6.0.3 统一契约) */
|
|
70
|
+
interface LoadMessagesInput {
|
|
71
|
+
appId: string;
|
|
72
|
+
/** 来自服务端可信上下文,不接受浏览器任意指定 */
|
|
73
|
+
tenantId?: string;
|
|
74
|
+
locale: string;
|
|
75
|
+
namespaces: string[];
|
|
76
|
+
release: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 渲染服务统一语言包 Provider 契约。
|
|
80
|
+
* YamlMessageProvider 与 ApiMessageProvider 输出完全相同的 MessageBundleSet,
|
|
81
|
+
* 消费方(如 DslLocalizer)只依赖此接口。
|
|
82
|
+
*/
|
|
83
|
+
interface MessageProvider {
|
|
84
|
+
load(input: LoadMessagesInput): Promise<MessageBundleSet>;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 浏览器/Node 中立的 fetch 响应形态 */
|
|
88
|
+
interface FetchLikeResponse {
|
|
89
|
+
status: number;
|
|
90
|
+
headers: {
|
|
91
|
+
get(name: string): string | null;
|
|
92
|
+
};
|
|
93
|
+
text(): Promise<string>;
|
|
94
|
+
}
|
|
95
|
+
/** 注入的 fetch 风格函数 */
|
|
96
|
+
type FetchLike = (url: string, init?: {
|
|
97
|
+
headers?: Record<string, string>;
|
|
98
|
+
}) => Promise<FetchLikeResponse>;
|
|
99
|
+
interface ApiMessageProviderOptions {
|
|
100
|
+
/** 语言包 API 地址,来自服务端应用配置,不接受浏览器任意指定 */
|
|
101
|
+
endpoint: string;
|
|
102
|
+
fetch: FetchLike;
|
|
103
|
+
/** 服务端凭据等附加请求头(如 Authorization) */
|
|
104
|
+
headers?: Record<string, string>;
|
|
105
|
+
}
|
|
106
|
+
/** load 扩展输入:可显式传入缓存的 ETag */
|
|
107
|
+
interface ApiLoadInput extends LoadMessagesInput {
|
|
108
|
+
etag?: string;
|
|
109
|
+
}
|
|
110
|
+
/** 携带缓存信息的加载结果 */
|
|
111
|
+
interface ApiLoadResult {
|
|
112
|
+
bundleSet: MessageBundleSet;
|
|
113
|
+
etag?: string;
|
|
114
|
+
/** 304 复用已校验缓存包时为 true */
|
|
115
|
+
notModified: boolean;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* 语言包 API Provider(设计 6.0.3 / 6.1)。
|
|
119
|
+
*
|
|
120
|
+
* 校验 HTTP 状态与 Content-Type(必须 application/json)、解析 JSON、
|
|
121
|
+
* 校验 envelope 协议字段与 format;返回 YAML 或内嵌 YAML 字符串按
|
|
122
|
+
* MESSAGE_PROTOCOL_ERROR 处理,不切换解析方式。
|
|
123
|
+
*
|
|
124
|
+
* ETag / If-None-Match:provider 内部按缓存键(appId/tenant/locale/
|
|
125
|
+
* namespaces/release)记录最近校验通过的包及其 ETag;304 时复用该缓存,
|
|
126
|
+
* 结果携带 notModified 标记。也可通过 load 输入的 etag 显式指定。
|
|
127
|
+
*/
|
|
128
|
+
declare class ApiMessageProvider implements MessageProvider {
|
|
129
|
+
private readonly options;
|
|
130
|
+
private readonly cache;
|
|
131
|
+
constructor(options: ApiMessageProviderOptions);
|
|
132
|
+
/** MessageProvider 契约实现 */
|
|
133
|
+
load(input: ApiLoadInput): Promise<MessageBundleSet>;
|
|
134
|
+
/** 加载并返回缓存信息(ETag / notModified) */
|
|
135
|
+
loadWithCacheInfo(input: ApiLoadInput): Promise<ApiLoadResult>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
declare function isValidMessageKey(key: string): boolean;
|
|
139
|
+
/**
|
|
140
|
+
* 校验扁平词条表:顶层必须为普通对象,键名合法,值全部为字符串。
|
|
141
|
+
* 不合法时抛出指定 code 的 I18nError。
|
|
142
|
+
*/
|
|
143
|
+
declare function assertMessages(value: unknown, context: string, code: I18nErrorCode): Record<string, string>;
|
|
144
|
+
/** namespace 间完整 key 冲突检查(结果与 namespace 遍历顺序无关) */
|
|
145
|
+
declare function assertNoCrossNamespaceKeyConflicts(bundles: Record<string, Record<string, string>>, code: I18nErrorCode): void;
|
|
146
|
+
interface EnvelopeExpectation {
|
|
147
|
+
appId: string;
|
|
148
|
+
locale: string;
|
|
149
|
+
release: string;
|
|
150
|
+
namespaces: readonly string[];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 校验语言包 API 的 JSON envelope(设计 6.1)。
|
|
154
|
+
* 结构/协议字段问题抛 MESSAGE_PROTOCOL_ERROR;缺失请求的 namespace 抛 NAMESPACE_NOT_FOUND。
|
|
155
|
+
*/
|
|
156
|
+
declare function validateBundleSetEnvelope(data: unknown, expected: EnvelopeExpectation): MessageBundleSet;
|
|
157
|
+
|
|
158
|
+
declare class TranslatableFieldRegistry {
|
|
159
|
+
private readonly componentFields;
|
|
160
|
+
private readonly actionFields;
|
|
161
|
+
/** 注册组件 type 的可翻译字段路径(可重复调用,累积合并) */
|
|
162
|
+
register(componentType: string, fields: string | readonly string[]): this;
|
|
163
|
+
/** 注册动作名的可翻译参数字段路径(如 message 动作的 `params.text`) */
|
|
164
|
+
registerAction(actionName: string, fields: string | readonly string[]): this;
|
|
165
|
+
/**
|
|
166
|
+
* 判断组件字段是否已注册。`canonicalPath` 为规范化路径
|
|
167
|
+
* (数组下标段写作 `[*]`,如 `props.columns[*].title`)。
|
|
168
|
+
*/
|
|
169
|
+
isTranslatable(componentType: string | undefined, canonicalPath: string): boolean;
|
|
170
|
+
/** 判断动作参数字段是否已注册 */
|
|
171
|
+
isTranslatableActionField(actionName: string, canonicalPath: string): boolean;
|
|
172
|
+
/** 已注册组件 type 列表(诊断/调试用) */
|
|
173
|
+
registeredComponents(): string[];
|
|
174
|
+
/** 已注册动作名列表(诊断/调试用) */
|
|
175
|
+
registeredActions(): string[];
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 内置注册表(设计 4.4 常用展示字段):
|
|
179
|
+
* Button/Text/Input/Table 列/Select 选项,以及 message / confirm 动作参数。
|
|
180
|
+
*/
|
|
181
|
+
declare function createDefaultTranslatableFieldRegistry(): TranslatableFieldRegistry;
|
|
182
|
+
/**
|
|
183
|
+
* 共享默认注册表(惰性创建)。请勿原地修改返回的实例;
|
|
184
|
+
* 需要自定义时通过 `createDefaultTranslatableFieldRegistry()` 或
|
|
185
|
+
* `new TranslatableFieldRegistry()` 创建独立副本。
|
|
186
|
+
*/
|
|
187
|
+
declare function getDefaultTranslatableFieldRegistry(): TranslatableFieldRegistry;
|
|
188
|
+
|
|
189
|
+
/** 转义单个 JSON Pointer 段(`~` → `~0`、`/` → `~1`) */
|
|
190
|
+
declare function escapeJsonPointerSegment(segment: string): string;
|
|
191
|
+
/**
|
|
192
|
+
* 解析 JSON Pointer(RFC 6901)为段数组。
|
|
193
|
+
* 空串返回 `[]`(指整个文档);`~0`/`~1` 之外的转义、非 `/` 开头均抛 BINDING_INVALID。
|
|
194
|
+
*/
|
|
195
|
+
declare function parseJsonPointer(pointer: string): string[];
|
|
196
|
+
/** bindings 定位结果:父容器、末段键与当前值 */
|
|
197
|
+
interface ResolvedJsonPointer {
|
|
198
|
+
parent: Record<string, unknown> | unknown[];
|
|
199
|
+
key: string | number;
|
|
200
|
+
value: unknown;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* 按段数组定位目标字段。空指针(指整个文档)、中间段或末段不存在、
|
|
204
|
+
* 数组下标非法均抛 BINDING_INVALID。
|
|
205
|
+
*/
|
|
206
|
+
declare function resolveJsonPointer(root: unknown, segments: readonly string[], pointer: string): ResolvedJsonPointer;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* DslLocalizer(设计第 4、6、7、8 节,缺口 G03/G04/G17)。
|
|
210
|
+
*
|
|
211
|
+
* 纯转换入口:语言包作为参数显式传入,不在遍历组件时自行请求。
|
|
212
|
+
* 统一处理三种声明方式(`$i18n.messages`、`$i18n.key`、页面 `i18n.bindings`),
|
|
213
|
+
* 返回已本地化的新对象(不修改输入);编译后移除作者态 `i18n` 字段。
|
|
214
|
+
*/
|
|
215
|
+
/** 翻译描述(bindings 值与 `$i18n` 内层共用形态) */
|
|
216
|
+
type TranslationDescriptor = I18nKeyRef | I18nInlineMessages;
|
|
217
|
+
/** 页面作者态 i18n 字段(设计 4.2) */
|
|
218
|
+
interface AuthorPageI18n {
|
|
219
|
+
namespaces?: string[];
|
|
220
|
+
bindings?: Record<string, TranslationDescriptor>;
|
|
221
|
+
}
|
|
222
|
+
/** 作者态 Page DSL(PageDsl + 顶层 i18n 字段) */
|
|
223
|
+
type AuthorPageDsl = PageDsl & {
|
|
224
|
+
i18n?: AuthorPageI18n;
|
|
225
|
+
};
|
|
226
|
+
/** 显式传入的语言包链:current 为当前 locale,fallbacks 有序(显式语言级回退 → defaultLocale) */
|
|
227
|
+
interface LanguageBundles {
|
|
228
|
+
current: MessageBundleSet;
|
|
229
|
+
fallbacks?: MessageBundleSet[];
|
|
230
|
+
}
|
|
231
|
+
/** 词条未在当前 locale 命中时的实际命中方式 */
|
|
232
|
+
type MissingResolution = 'fallback-locale' | 'default-locale' | 'fallback' | 'implicit-fallback' | 'key' | 'missing-text';
|
|
233
|
+
interface LocalizeDiagnostic {
|
|
234
|
+
type: 'missing-translation' | 'missing-param';
|
|
235
|
+
/** 展示用文档路径(JSON Pointer 形态,数组为真实下标) */
|
|
236
|
+
path: string;
|
|
237
|
+
locale: string;
|
|
238
|
+
key?: string;
|
|
239
|
+
param?: string;
|
|
240
|
+
resolution?: MissingResolution | 'placeholder';
|
|
241
|
+
}
|
|
242
|
+
interface LocalizePageDslInput {
|
|
243
|
+
page: AuthorPageDsl;
|
|
244
|
+
locale: string;
|
|
245
|
+
defaultLocale: string;
|
|
246
|
+
languageBundles: LanguageBundles;
|
|
247
|
+
registry?: TranslatableFieldRegistry;
|
|
248
|
+
onDiagnostic?: (diagnostic: LocalizeDiagnostic) => void;
|
|
249
|
+
}
|
|
250
|
+
/** 内联描述无 key 且所有回退失败时的统一缺失文案 */
|
|
251
|
+
declare const MISSING_TRANSLATION_TEXT = "[missing translation]";
|
|
252
|
+
/**
|
|
253
|
+
* 纯转换入口(设计第 6 节签名)。返回已本地化的新 Page DSL 对象,
|
|
254
|
+
* 不修改输入(page / languageBundles 均不被改写);作者态 `i18n` 字段被移除。
|
|
255
|
+
*/
|
|
256
|
+
declare function localizePageDsl(input: LocalizePageDslInput): PageDsl;
|
|
257
|
+
|
|
258
|
+
export { type AcceptLanguageEntry, type ApiLoadInput, type ApiLoadResult, ApiMessageProvider, type ApiMessageProviderOptions, type AuthorPageDsl, type AuthorPageI18n, type EnvelopeExpectation, type FetchLike, type FetchLikeResponse, I18nError, type I18nErrorCode, type LanguageBundles, type LoadMessagesInput, type LocaleResolverConfig, type LocaleSource, type LocalizeDiagnostic, type LocalizePageDslInput, MISSING_TRANSLATION_TEXT, type MessageProvider, type MissingResolution, type ResolveLocaleInput, type ResolvedJsonPointer, type ResolvedRequestLocale, TranslatableFieldRegistry, type TranslationDescriptor, assertMessages, assertNoCrossNamespaceKeyConflicts, createDefaultTranslatableFieldRegistry, escapeJsonPointerSegment, getDefaultTranslatableFieldRegistry, isI18nError, isValidMessageKey, localizePageDsl, normalizeLocaleTag, parseAcceptLanguage, parseJsonPointer, resolveJsonPointer, resolveRequestLocale, validateBundleSetEnvelope };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ApiMessageProvider,
|
|
3
|
+
I18nError,
|
|
4
|
+
MISSING_TRANSLATION_TEXT,
|
|
5
|
+
TranslatableFieldRegistry,
|
|
6
|
+
assertMessages,
|
|
7
|
+
assertNoCrossNamespaceKeyConflicts,
|
|
8
|
+
createDefaultTranslatableFieldRegistry,
|
|
9
|
+
escapeJsonPointerSegment,
|
|
10
|
+
getDefaultTranslatableFieldRegistry,
|
|
11
|
+
isI18nError,
|
|
12
|
+
isValidMessageKey,
|
|
13
|
+
localizePageDsl,
|
|
14
|
+
normalizeLocaleTag,
|
|
15
|
+
parseAcceptLanguage,
|
|
16
|
+
parseJsonPointer,
|
|
17
|
+
resolveJsonPointer,
|
|
18
|
+
resolveRequestLocale,
|
|
19
|
+
validateBundleSetEnvelope
|
|
20
|
+
} from "./chunk-3YCHXWF6.js";
|
|
21
|
+
export {
|
|
22
|
+
ApiMessageProvider,
|
|
23
|
+
I18nError,
|
|
24
|
+
MISSING_TRANSLATION_TEXT,
|
|
25
|
+
TranslatableFieldRegistry,
|
|
26
|
+
assertMessages,
|
|
27
|
+
assertNoCrossNamespaceKeyConflicts,
|
|
28
|
+
createDefaultTranslatableFieldRegistry,
|
|
29
|
+
escapeJsonPointerSegment,
|
|
30
|
+
getDefaultTranslatableFieldRegistry,
|
|
31
|
+
isI18nError,
|
|
32
|
+
isValidMessageKey,
|
|
33
|
+
localizePageDsl,
|
|
34
|
+
normalizeLocaleTag,
|
|
35
|
+
parseAcceptLanguage,
|
|
36
|
+
parseJsonPointer,
|
|
37
|
+
resolveJsonPointer,
|
|
38
|
+
resolveRequestLocale,
|
|
39
|
+
validateBundleSetEnvelope
|
|
40
|
+
};
|