@_linked/translation 0.2.2
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 +102 -0
- package/lib/cjs/data/translation.json +8 -0
- package/lib/esm/archive.d.ts +133 -0
- package/lib/esm/archive.js +567 -0
- package/lib/esm/archive.js.map +1 -0
- package/lib/esm/authorization.d.ts +12 -0
- package/lib/esm/authorization.js +10 -0
- package/lib/esm/authorization.js.map +1 -0
- package/lib/esm/backend.d.ts +1 -0
- package/lib/esm/backend.js +3 -0
- package/lib/esm/backend.js.map +1 -0
- package/lib/esm/cdn-loader.d.ts +40 -0
- package/lib/esm/cdn-loader.js +200 -0
- package/lib/esm/cdn-loader.js.map +1 -0
- package/lib/esm/checks.d.ts +56 -0
- package/lib/esm/checks.js +288 -0
- package/lib/esm/checks.js.map +1 -0
- package/lib/esm/compile.d.ts +64 -0
- package/lib/esm/compile.js +99 -0
- package/lib/esm/compile.js.map +1 -0
- package/lib/esm/core/messages.d.ts +25 -0
- package/lib/esm/core/messages.js +76 -0
- package/lib/esm/core/messages.js.map +1 -0
- package/lib/esm/data/translation.json +8 -0
- package/lib/esm/discovery.d.ts +97 -0
- package/lib/esm/discovery.js +365 -0
- package/lib/esm/discovery.js.map +1 -0
- package/lib/esm/exchange.d.ts +100 -0
- package/lib/esm/exchange.js +223 -0
- package/lib/esm/exchange.js.map +1 -0
- package/lib/esm/export.d.ts +28 -0
- package/lib/esm/export.js +92 -0
- package/lib/esm/export.js.map +1 -0
- package/lib/esm/formats/csv.d.ts +8 -0
- package/lib/esm/formats/csv.js +397 -0
- package/lib/esm/formats/csv.js.map +1 -0
- package/lib/esm/formats/json.d.ts +30 -0
- package/lib/esm/formats/json.js +459 -0
- package/lib/esm/formats/json.js.map +1 -0
- package/lib/esm/formats/xliff.d.ts +12 -0
- package/lib/esm/formats/xliff.js +577 -0
- package/lib/esm/formats/xliff.js.map +1 -0
- package/lib/esm/import.d.ts +197 -0
- package/lib/esm/import.js +391 -0
- package/lib/esm/import.js.map +1 -0
- package/lib/esm/index.d.ts +42 -0
- package/lib/esm/index.js +34 -0
- package/lib/esm/index.js.map +1 -0
- package/lib/esm/key-sync-node.d.ts +29 -0
- package/lib/esm/key-sync-node.js +174 -0
- package/lib/esm/key-sync-node.js.map +1 -0
- package/lib/esm/key-sync.d.ts +46 -0
- package/lib/esm/key-sync.js +114 -0
- package/lib/esm/key-sync.js.map +1 -0
- package/lib/esm/key-version.d.ts +50 -0
- package/lib/esm/key-version.js +134 -0
- package/lib/esm/key-version.js.map +1 -0
- package/lib/esm/languages.d.ts +18 -0
- package/lib/esm/languages.js +74 -0
- package/lib/esm/languages.js.map +1 -0
- package/lib/esm/linked-discovery.d.ts +44 -0
- package/lib/esm/linked-discovery.js +267 -0
- package/lib/esm/linked-discovery.js.map +1 -0
- package/lib/esm/message-format.d.ts +41 -0
- package/lib/esm/message-format.js +133 -0
- package/lib/esm/message-format.js.map +1 -0
- package/lib/esm/mt.d.ts +111 -0
- package/lib/esm/mt.js +142 -0
- package/lib/esm/mt.js.map +1 -0
- package/lib/esm/ontologies/translation.d.ts +203 -0
- package/lib/esm/ontologies/translation.js +219 -0
- package/lib/esm/ontologies/translation.js.map +1 -0
- package/lib/esm/package.d.ts +4 -0
- package/lib/esm/package.js +11 -0
- package/lib/esm/package.js.map +1 -0
- package/lib/esm/react.d.ts +55 -0
- package/lib/esm/react.js +127 -0
- package/lib/esm/react.js.map +1 -0
- package/lib/esm/records.d.ts +151 -0
- package/lib/esm/records.js +2 -0
- package/lib/esm/records.js.map +1 -0
- package/lib/esm/release.d.ts +198 -0
- package/lib/esm/release.js +435 -0
- package/lib/esm/release.js.map +1 -0
- package/lib/esm/shape-catalog.d.ts +79 -0
- package/lib/esm/shape-catalog.js +118 -0
- package/lib/esm/shape-catalog.js.map +1 -0
- package/lib/esm/shapes/GlossaryTerm.d.ts +28 -0
- package/lib/esm/shapes/GlossaryTerm.js +94 -0
- package/lib/esm/shapes/GlossaryTerm.js.map +1 -0
- package/lib/esm/shapes/TranslationInventoryOrigin.d.ts +33 -0
- package/lib/esm/shapes/TranslationInventoryOrigin.js +209 -0
- package/lib/esm/shapes/TranslationInventoryOrigin.js.map +1 -0
- package/lib/esm/shapes/TranslationKey.d.ts +92 -0
- package/lib/esm/shapes/TranslationKey.js +194 -0
- package/lib/esm/shapes/TranslationKey.js.map +1 -0
- package/lib/esm/shapes/TranslationKeyVersion.d.ts +19 -0
- package/lib/esm/shapes/TranslationKeyVersion.js +125 -0
- package/lib/esm/shapes/TranslationKeyVersion.js.map +1 -0
- package/lib/esm/shapes/TranslationLanguage.d.ts +15 -0
- package/lib/esm/shapes/TranslationLanguage.js +102 -0
- package/lib/esm/shapes/TranslationLanguage.js.map +1 -0
- package/lib/esm/shapes/TranslationProvider.d.ts +409 -0
- package/lib/esm/shapes/TranslationProvider.js +1376 -0
- package/lib/esm/shapes/TranslationProvider.js.map +1 -0
- package/lib/esm/shapes/TranslationRelease.d.ts +36 -0
- package/lib/esm/shapes/TranslationRelease.js +149 -0
- package/lib/esm/shapes/TranslationRelease.js.map +1 -0
- package/lib/esm/shapes/TranslationRevision.d.ts +39 -0
- package/lib/esm/shapes/TranslationRevision.js +159 -0
- package/lib/esm/shapes/TranslationRevision.js.map +1 -0
- package/lib/esm/shapes/TranslationUnit.d.ts +26 -0
- package/lib/esm/shapes/TranslationUnit.js +111 -0
- package/lib/esm/shapes/TranslationUnit.js.map +1 -0
- package/package.json +134 -0
- package/src/archive.ts +894 -0
- package/src/authorization.ts +33 -0
- package/src/backend.ts +2 -0
- package/src/cdn-loader.ts +264 -0
- package/src/checks.ts +413 -0
- package/src/compile.ts +168 -0
- package/src/core/messages.ts +106 -0
- package/src/data/translation.json +8 -0
- package/src/discovery.ts +594 -0
- package/src/exchange.ts +428 -0
- package/src/export.ts +135 -0
- package/src/formats/csv.ts +459 -0
- package/src/formats/json.ts +587 -0
- package/src/formats/xliff.ts +708 -0
- package/src/import.ts +648 -0
- package/src/index.ts +207 -0
- package/src/key-sync-node.ts +269 -0
- package/src/key-sync.ts +168 -0
- package/src/key-version.ts +206 -0
- package/src/languages.ts +102 -0
- package/src/linked-discovery.ts +385 -0
- package/src/message-format.ts +214 -0
- package/src/mt.ts +248 -0
- package/src/ontologies/translation.ts +234 -0
- package/src/package.ts +19 -0
- package/src/react.tsx +250 -0
- package/src/records.ts +180 -0
- package/src/release.ts +726 -0
- package/src/shape-catalog.ts +198 -0
- package/src/shapes/GlossaryTerm.ts +61 -0
- package/src/shapes/TranslationInventoryOrigin.ts +131 -0
- package/src/shapes/TranslationKey.ts +174 -0
- package/src/shapes/TranslationKeyVersion.ts +77 -0
- package/src/shapes/TranslationLanguage.ts +51 -0
- package/src/shapes/TranslationProvider.ts +1755 -0
- package/src/shapes/TranslationRelease.ts +114 -0
- package/src/shapes/TranslationRevision.ts +105 -0
- package/src/shapes/TranslationUnit.ts +72 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TranslationEntryRecord,
|
|
3
|
+
TranslationState,
|
|
4
|
+
} from './records.js';
|
|
5
|
+
import type { TranslationDiscoverySource } from './discovery.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Code-canonical translations shipped beside one reusable LINKED shape.
|
|
9
|
+
* Packages may expose this object from code or serialize the same contract as
|
|
10
|
+
* JSON for Host Agent discovery without executing package code.
|
|
11
|
+
*/
|
|
12
|
+
export interface ShapeTranslationCatalog {
|
|
13
|
+
schemaVersion: 1;
|
|
14
|
+
packageName: string;
|
|
15
|
+
/** Canonical SHACL node-shape IRI, not a display label or filesystem path. */
|
|
16
|
+
shapeIri: string;
|
|
17
|
+
/** Optional stable domain-class IRI used for semantic browsing. */
|
|
18
|
+
targetClass?: string;
|
|
19
|
+
entries: ShapeTranslationCatalogEntry[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ShapeTranslationCatalogEntry {
|
|
23
|
+
key: string;
|
|
24
|
+
sourceText: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
namespace?: string;
|
|
27
|
+
/** Stable predicate IRI when this message describes a shape property. */
|
|
28
|
+
propertyIri?: string;
|
|
29
|
+
format?: 'simple' | 'icu';
|
|
30
|
+
/** Curated BCP-47 language values supplied by the package. */
|
|
31
|
+
translations?: Record<
|
|
32
|
+
string,
|
|
33
|
+
string | { text: string; state?: TranslationState }
|
|
34
|
+
>;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface ShapeTranslationCatalogTarget {
|
|
38
|
+
listEntries(data: { appId: string }): Promise<TranslationEntryRecord[]>;
|
|
39
|
+
upsertKey(data: {
|
|
40
|
+
appId: string;
|
|
41
|
+
key: string;
|
|
42
|
+
sourceText: string;
|
|
43
|
+
namespace?: string;
|
|
44
|
+
description?: string;
|
|
45
|
+
kind: 'ui';
|
|
46
|
+
format?: 'simple' | 'icu';
|
|
47
|
+
ofShape: string;
|
|
48
|
+
ofProperty?: string;
|
|
49
|
+
fromPackage: string;
|
|
50
|
+
}): Promise<unknown>;
|
|
51
|
+
upsertUnit(data: {
|
|
52
|
+
appId: string;
|
|
53
|
+
key: string;
|
|
54
|
+
language: string;
|
|
55
|
+
text: string;
|
|
56
|
+
state: TranslationState;
|
|
57
|
+
}): Promise<unknown>;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface ShapeTranslationInstallReport {
|
|
61
|
+
createdKeys: string[];
|
|
62
|
+
createdUnits: Array<{ key: string; language: string }>;
|
|
63
|
+
skippedExistingKeys: string[];
|
|
64
|
+
skippedExistingUnits: Array<{ key: string; language: string }>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function requireString(value: unknown, label: string): string {
|
|
68
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
69
|
+
throw new Error(`${label} is required.`);
|
|
70
|
+
}
|
|
71
|
+
return value.trim();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Validate and freeze the package-owned declaration at module load time. */
|
|
75
|
+
export function defineShapeTranslationCatalog(
|
|
76
|
+
catalog: ShapeTranslationCatalog,
|
|
77
|
+
): Readonly<ShapeTranslationCatalog> {
|
|
78
|
+
if (catalog?.schemaVersion !== 1) {
|
|
79
|
+
throw new Error('Shape translation catalog schemaVersion must be 1.');
|
|
80
|
+
}
|
|
81
|
+
requireString(catalog.packageName, 'packageName');
|
|
82
|
+
requireString(catalog.shapeIri, 'shapeIri');
|
|
83
|
+
if (!Array.isArray(catalog.entries)) {
|
|
84
|
+
throw new Error('Shape translation catalog entries must be an array.');
|
|
85
|
+
}
|
|
86
|
+
const keys = new Set<string>();
|
|
87
|
+
for (const entry of catalog.entries) {
|
|
88
|
+
const key = requireString(entry?.key, 'entry.key');
|
|
89
|
+
requireString(entry?.sourceText, `sourceText for ${key}`);
|
|
90
|
+
if (keys.has(key)) throw new Error(`Duplicate shape translation key "${key}".`);
|
|
91
|
+
keys.add(key);
|
|
92
|
+
}
|
|
93
|
+
return Object.freeze(catalog);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Adapt the existing schema-v1 catalog without changing its install contract. */
|
|
97
|
+
export function shapeCatalogTranslationDiscoverySource(
|
|
98
|
+
input: ShapeTranslationCatalog,
|
|
99
|
+
): TranslationDiscoverySource {
|
|
100
|
+
const catalog = defineShapeTranslationCatalog(input);
|
|
101
|
+
return {
|
|
102
|
+
name: `shape-catalog:${catalog.packageName}:${catalog.shapeIri}`,
|
|
103
|
+
async *discover() {
|
|
104
|
+
for (const entry of catalog.entries) {
|
|
105
|
+
yield {
|
|
106
|
+
schemaVersion: 1,
|
|
107
|
+
key: entry.key,
|
|
108
|
+
sourceText: entry.sourceText,
|
|
109
|
+
kind: 'ui',
|
|
110
|
+
format: entry.format ?? 'simple',
|
|
111
|
+
...(entry.namespace ? { namespace: entry.namespace } : {}),
|
|
112
|
+
...(entry.description ? { description: entry.description } : {}),
|
|
113
|
+
provenance: {
|
|
114
|
+
source: 'package',
|
|
115
|
+
sourceId: `${catalog.packageName}:${catalog.shapeIri}`,
|
|
116
|
+
authoritative: true,
|
|
117
|
+
ownerIri: catalog.shapeIri,
|
|
118
|
+
shapeIri: catalog.shapeIri,
|
|
119
|
+
fromPackage: catalog.packageName,
|
|
120
|
+
...(catalog.targetClass
|
|
121
|
+
? { targetClass: catalog.targetClass }
|
|
122
|
+
: {}),
|
|
123
|
+
...(entry.propertyIri
|
|
124
|
+
? { propertyIri: entry.propertyIri }
|
|
125
|
+
: {}),
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Seed only missing app values for the currently activated languages.
|
|
135
|
+
* Existing project-authored keys and units always win over package defaults.
|
|
136
|
+
*/
|
|
137
|
+
export async function installShapeTranslationCatalog(
|
|
138
|
+
target: ShapeTranslationCatalogTarget,
|
|
139
|
+
input: {
|
|
140
|
+
appId: string;
|
|
141
|
+
catalog: ShapeTranslationCatalog;
|
|
142
|
+
activeLanguages: Iterable<string>;
|
|
143
|
+
},
|
|
144
|
+
): Promise<ShapeTranslationInstallReport> {
|
|
145
|
+
const appId = requireString(input.appId, 'appId');
|
|
146
|
+
const catalog = defineShapeTranslationCatalog(input.catalog);
|
|
147
|
+
const activeLanguages = new Set(
|
|
148
|
+
[...input.activeLanguages].map((language) => language.trim()).filter(Boolean),
|
|
149
|
+
);
|
|
150
|
+
const existing = new Map(
|
|
151
|
+
(await target.listEntries({ appId })).map((entry) => [entry.key, entry]),
|
|
152
|
+
);
|
|
153
|
+
const report: ShapeTranslationInstallReport = {
|
|
154
|
+
createdKeys: [],
|
|
155
|
+
createdUnits: [],
|
|
156
|
+
skippedExistingKeys: [],
|
|
157
|
+
skippedExistingUnits: [],
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
for (const entry of catalog.entries) {
|
|
161
|
+
const current = existing.get(entry.key);
|
|
162
|
+
if (current) report.skippedExistingKeys.push(entry.key);
|
|
163
|
+
else {
|
|
164
|
+
await target.upsertKey({
|
|
165
|
+
appId,
|
|
166
|
+
key: entry.key,
|
|
167
|
+
sourceText: entry.sourceText,
|
|
168
|
+
namespace: entry.namespace,
|
|
169
|
+
description: entry.description,
|
|
170
|
+
kind: 'ui',
|
|
171
|
+
format: entry.format,
|
|
172
|
+
ofShape: catalog.shapeIri,
|
|
173
|
+
ofProperty: entry.propertyIri,
|
|
174
|
+
fromPackage: catalog.packageName,
|
|
175
|
+
});
|
|
176
|
+
report.createdKeys.push(entry.key);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
for (const language of [...activeLanguages].sort()) {
|
|
180
|
+
const value = entry.translations?.[language];
|
|
181
|
+
if (value === undefined) continue;
|
|
182
|
+
if (current?.units[language]) {
|
|
183
|
+
report.skippedExistingUnits.push({ key: entry.key, language });
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
const unit = typeof value === 'string' ? { text: value } : value;
|
|
187
|
+
await target.upsertUnit({
|
|
188
|
+
appId,
|
|
189
|
+
key: entry.key,
|
|
190
|
+
language,
|
|
191
|
+
text: unit.text,
|
|
192
|
+
state: unit.state ?? 'reviewed',
|
|
193
|
+
});
|
|
194
|
+
report.createdUnits.push({ key: entry.key, language });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return report;
|
|
198
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Shape } from '@_linked/core/shapes/Shape';
|
|
2
|
+
import { literalProperty } from '@_linked/core/shapes/SHACL';
|
|
3
|
+
import { tr } from '../ontologies/translation.js';
|
|
4
|
+
import { linkedShape } from '../package.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A glossary entry that steers machine translation (Plan 014 AD-L) — e.g. keep
|
|
8
|
+
* a brand/term consistent or fixed across languages. Fed to the MT provider's
|
|
9
|
+
* prompt. Per-app content like the rest of the translation model.
|
|
10
|
+
*/
|
|
11
|
+
@linkedShape
|
|
12
|
+
export class GlossaryTerm extends Shape {
|
|
13
|
+
static targetClass = tr.GlossaryTerm;
|
|
14
|
+
|
|
15
|
+
/** The source term (English). */
|
|
16
|
+
@literalProperty({ path: tr.term, maxCount: 1 })
|
|
17
|
+
get term(): string {
|
|
18
|
+
return '';
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Preferred translation for the target language (optional; empty = keep as-is). */
|
|
22
|
+
@literalProperty({ path: tr.glossaryTranslation, maxCount: 1 })
|
|
23
|
+
get translation(): string {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Target language this entry applies to (empty = all). */
|
|
28
|
+
@literalProperty({ path: tr.glossaryLanguage, maxCount: 1 })
|
|
29
|
+
get language(): string {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@literalProperty({ path: tr.description, maxCount: 1 })
|
|
34
|
+
get description(): string {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Termbase entry type: 'prefer' advises {@link translation}; 'require'
|
|
40
|
+
* enforces that wording whenever the source uses the term; 'keep' =
|
|
41
|
+
* do-not-translate, preserved exactly (proper
|
|
42
|
+
* nouns, stay-one-language words); 'forbid' = never use this word/spelling —
|
|
43
|
+
* {@link useInstead} names the replacement (alternative-spelling policing).
|
|
44
|
+
*/
|
|
45
|
+
@literalProperty({ path: tr.termType, maxCount: 1 })
|
|
46
|
+
get termType(): string {
|
|
47
|
+
return 'prefer';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Replacement wording for a 'forbid' entry. */
|
|
51
|
+
@literalProperty({ path: tr.useInstead, maxCount: 1 })
|
|
52
|
+
get useInstead(): string {
|
|
53
|
+
return '';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Match with exact casing (proper nouns / all-caps brand styling). */
|
|
57
|
+
@literalProperty({ path: tr.caseSensitive, maxCount: 1 })
|
|
58
|
+
get caseSensitive(): boolean {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { Shape } from '@_linked/core/shapes/Shape';
|
|
2
|
+
import { literalProperty, objectProperty } from '@_linked/core/shapes/SHACL';
|
|
3
|
+
import { xsd } from '@_linked/core/ontologies/xsd';
|
|
4
|
+
import { tr } from '../ontologies/translation.js';
|
|
5
|
+
import { linkedShape } from '../package.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* One observed origin for a branch translation-inventory item.
|
|
9
|
+
*
|
|
10
|
+
* Host code executes queries for this shape against the explicit branch
|
|
11
|
+
* metadata dataset. It is intentionally not globally pinned by the portable
|
|
12
|
+
* package: standalone LINKED apps may use a different metadata topology.
|
|
13
|
+
*/
|
|
14
|
+
@linkedShape
|
|
15
|
+
export class TranslationInventoryOrigin extends Shape {
|
|
16
|
+
static targetClass = tr.TranslationInventoryOrigin;
|
|
17
|
+
|
|
18
|
+
@objectProperty({ path: tr.ofApplication, maxCount: 1 })
|
|
19
|
+
get ofApplication(): string {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
@objectProperty({ path: tr.inventoryBranch, maxCount: 1 })
|
|
24
|
+
get branch(): string {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@literalProperty({ path: tr.inventoryIdentity, maxCount: 1 })
|
|
29
|
+
get identity(): string {
|
|
30
|
+
return '';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@literalProperty({ path: tr.key, maxCount: 1 })
|
|
34
|
+
get key(): string {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
@literalProperty({ path: tr.namespace, maxCount: 1 })
|
|
39
|
+
get namespace(): string {
|
|
40
|
+
return '';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
@literalProperty({ path: tr.sourceText, maxCount: 1 })
|
|
44
|
+
get sourceText(): string {
|
|
45
|
+
return '';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@literalProperty({ path: tr.kind, maxCount: 1 })
|
|
49
|
+
get kind(): string {
|
|
50
|
+
return 'ui';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@literalProperty({ path: tr.format, maxCount: 1 })
|
|
54
|
+
get format(): string {
|
|
55
|
+
return 'simple';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@literalProperty({ path: tr.description, maxCount: 1 })
|
|
59
|
+
get description(): string {
|
|
60
|
+
return '';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@literalProperty({ path: tr.inventoryStatus, maxCount: 1 })
|
|
64
|
+
get status(): string {
|
|
65
|
+
return 'pending';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@literalProperty({ path: tr.inventorySource, maxCount: 1 })
|
|
69
|
+
get sourceKind(): string {
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@literalProperty({ path: tr.inventorySourceId, maxCount: 1 })
|
|
74
|
+
get sourceId(): string {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@literalProperty({ path: tr.inventoryAuthoritative, maxCount: 1 })
|
|
79
|
+
get authoritative(): boolean {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@literalProperty({ path: tr.inventoryFile, maxCount: 1 })
|
|
84
|
+
get file(): string {
|
|
85
|
+
return '';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@literalProperty({ path: tr.inventoryLine, datatype: xsd.integer, maxCount: 1 })
|
|
89
|
+
get line(): number {
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@objectProperty({ path: tr.inventoryOwner, maxCount: 1 })
|
|
94
|
+
get ownerIri(): string {
|
|
95
|
+
return '';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@objectProperty({ path: tr.inventoryShape, maxCount: 1 })
|
|
99
|
+
get shapeIri(): string {
|
|
100
|
+
return '';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@objectProperty({ path: tr.inventoryProperty, maxCount: 1 })
|
|
104
|
+
get propertyIri(): string {
|
|
105
|
+
return '';
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@objectProperty({ path: tr.inventoryNode, maxCount: 1 })
|
|
109
|
+
get nodeIri(): string {
|
|
110
|
+
return '';
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@literalProperty({ path: tr.fromPackage, maxCount: 1 })
|
|
114
|
+
get fromPackage(): string {
|
|
115
|
+
return '';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
@literalProperty({ path: tr.inventoryTargetClass, maxCount: 1 })
|
|
119
|
+
get targetClass(): string {
|
|
120
|
+
return '';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@literalProperty({
|
|
124
|
+
path: tr.inventoryObservedAt,
|
|
125
|
+
datatype: xsd.dateTime,
|
|
126
|
+
maxCount: 1,
|
|
127
|
+
})
|
|
128
|
+
get observedAt(): Date {
|
|
129
|
+
return new Date(0);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { Shape } from '@_linked/core/shapes/Shape';
|
|
2
|
+
import { literalProperty, objectProperty } from '@_linked/core/shapes/SHACL';
|
|
3
|
+
import { Server } from '@_linked/server-utils/utils/Server';
|
|
4
|
+
import { tr } from '../ontologies/translation.js';
|
|
5
|
+
import { linkedShape } from '../package.js';
|
|
6
|
+
import type {
|
|
7
|
+
TranslationEntryRecord,
|
|
8
|
+
TranslationKeyVersionRecord,
|
|
9
|
+
TranslationState,
|
|
10
|
+
} from '../records.js';
|
|
11
|
+
import type { TranslationMessages } from '../core/messages.js';
|
|
12
|
+
import type { TranslationKeyVersion } from './TranslationKeyVersion.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A translatable key (Plan 014 AD-H). Covers both UI-string keys (`kind:'ui'`)
|
|
16
|
+
* and graph-content translations (`kind:'content'` + `ofNode`/`ofField`), unified
|
|
17
|
+
* in one scheme. `sourceText` is the canonical English (R7); `format` pins the
|
|
18
|
+
* message syntax so imported FormatSimple strings aren't reinterpreted as ICU
|
|
19
|
+
* (R8). Named `TranslationKey` (its per-language values are {@link TranslationUnit}s,
|
|
20
|
+
* not `Translation` — avoids collision with serve's legacy shape, R13).
|
|
21
|
+
*/
|
|
22
|
+
@linkedShape
|
|
23
|
+
export class TranslationKey extends Shape {
|
|
24
|
+
static targetClass = tr.TranslationKey;
|
|
25
|
+
|
|
26
|
+
/** Dotted namespace grouping, e.g. "account". */
|
|
27
|
+
@literalProperty({ path: tr.namespace, maxCount: 1 })
|
|
28
|
+
get namespace(): string {
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** The key path, e.g. "account.title". */
|
|
33
|
+
@literalProperty({ path: tr.key, maxCount: 1 })
|
|
34
|
+
get key(): string {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Canonical English source string. */
|
|
39
|
+
@literalProperty({ path: tr.sourceText, maxCount: 1 })
|
|
40
|
+
get sourceText(): string {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@literalProperty({ path: tr.description, maxCount: 1 })
|
|
45
|
+
get description(): string {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** 'ui' (chrome string) | 'content' (graph field). */
|
|
50
|
+
@literalProperty({ path: tr.kind, maxCount: 1 })
|
|
51
|
+
get kind(): string {
|
|
52
|
+
return 'ui';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** IRI of the owning Application (translation content is app-scoped, AD-I). */
|
|
56
|
+
@objectProperty({ path: tr.ofApplication, maxCount: 1 })
|
|
57
|
+
get ofApplication(): string {
|
|
58
|
+
return '';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** For kind:'content' — the IRI of the translated subject node. */
|
|
62
|
+
@objectProperty({ path: tr.ofNode, maxCount: 1 })
|
|
63
|
+
get ofNode(): string {
|
|
64
|
+
return '';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** For kind:'content' — the field/predicate being translated. */
|
|
68
|
+
@literalProperty({ path: tr.ofField, maxCount: 1 })
|
|
69
|
+
get ofField(): string {
|
|
70
|
+
return '';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** SHACL node-shape IRI this packaged key accompanies. */
|
|
74
|
+
@objectProperty({ path: tr.ofShape, maxCount: 1 })
|
|
75
|
+
get ofShape(): string {
|
|
76
|
+
return '';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Stable predicate IRI when this key describes one shape property. */
|
|
80
|
+
@objectProperty({ path: tr.ofProperty, maxCount: 1 })
|
|
81
|
+
get ofProperty(): string {
|
|
82
|
+
return '';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Reusable package that supplied the seed value. */
|
|
86
|
+
@literalProperty({ path: tr.fromPackage, maxCount: 1 })
|
|
87
|
+
get fromPackage(): string {
|
|
88
|
+
return '';
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* True when this app copy of a shape-owned key has been edited locally and
|
|
93
|
+
* should NOT be overwritten by shape-route propagation (AD-N: "never
|
|
94
|
+
* overwrites an app's own override"). Set when the per-app editor changes the
|
|
95
|
+
* source of a key that carries `ofShape`.
|
|
96
|
+
*/
|
|
97
|
+
@literalProperty({ path: tr.overridden, maxCount: 1 })
|
|
98
|
+
get overridden(): boolean {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The shape's canonical source captured the moment this app first overrode the
|
|
104
|
+
* key — what "clear override" reverts to when no non-overridden sibling copy is
|
|
105
|
+
* available to read the current canonical from (AD-N).
|
|
106
|
+
*/
|
|
107
|
+
@literalProperty({ path: tr.shapeSource, maxCount: 1 })
|
|
108
|
+
get shapeSource(): string {
|
|
109
|
+
return '';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Message syntax: 'simple' (FormatSimple) | 'icu'. */
|
|
113
|
+
@literalProperty({ path: tr.format, maxCount: 1 })
|
|
114
|
+
get format(): string {
|
|
115
|
+
return 'simple';
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Current immutable source/argument contract. Populated by Plan 018 migration. */
|
|
119
|
+
@objectProperty({ path: tr.currentVersion, maxCount: 1 })
|
|
120
|
+
get currentVersion(): TranslationKeyVersion {
|
|
121
|
+
return undefined as any;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
static list(data: { appId: string }) {
|
|
125
|
+
return Server.call(this, 'listKeys', data);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Plain app-scoped records for authoring UIs; no live Shape crosses RPC. */
|
|
129
|
+
static listEntries(data: { appId: string }) {
|
|
130
|
+
return Server.call(this, 'listEntries', data) as Promise<
|
|
131
|
+
TranslationEntryRecord[]
|
|
132
|
+
>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
static listVersions(data: { appId: string; key?: string }) {
|
|
136
|
+
return Server.call(this, 'listKeyVersions', data) as Promise<
|
|
137
|
+
TranslationKeyVersionRecord[]
|
|
138
|
+
>;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Shape.upsert is the framework's typed graph-update builder. Keep the
|
|
142
|
+
// app-scoped translation RPC separate from that inherited API.
|
|
143
|
+
static upsertKey(data: {
|
|
144
|
+
appId: string;
|
|
145
|
+
key: string;
|
|
146
|
+
sourceText: string;
|
|
147
|
+
namespace?: string;
|
|
148
|
+
description?: string;
|
|
149
|
+
kind?: 'ui' | 'content';
|
|
150
|
+
ofNode?: string;
|
|
151
|
+
ofField?: string;
|
|
152
|
+
ofShape?: string;
|
|
153
|
+
ofProperty?: string;
|
|
154
|
+
fromPackage?: string;
|
|
155
|
+
format?: 'simple' | 'icu';
|
|
156
|
+
}): Promise<{ id: string }> {
|
|
157
|
+
return Server.call(this, 'upsertKey', data);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
static upsertUnit(data: {
|
|
161
|
+
appId: string;
|
|
162
|
+
key: string;
|
|
163
|
+
language: string;
|
|
164
|
+
text: string;
|
|
165
|
+
state?: TranslationState;
|
|
166
|
+
updatedBy?: string;
|
|
167
|
+
}) {
|
|
168
|
+
return Server.call(this, 'upsertUnit', data);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
static getMessages(data: { appId: string; language: string }) {
|
|
172
|
+
return Server.call(this, 'getMessages', data) as Promise<TranslationMessages>;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Shape } from '@_linked/core/shapes/Shape';
|
|
2
|
+
import { literalProperty, objectProperty } from '@_linked/core/shapes/SHACL';
|
|
3
|
+
import { xsd } from '@_linked/core/ontologies/xsd';
|
|
4
|
+
import { tr } from '../ontologies/translation.js';
|
|
5
|
+
import { linkedShape } from '../package.js';
|
|
6
|
+
import { TranslationKey } from './TranslationKey.js';
|
|
7
|
+
|
|
8
|
+
/** Immutable source text + runtime argument contract for one logical key. */
|
|
9
|
+
@linkedShape
|
|
10
|
+
export class TranslationKeyVersion extends Shape {
|
|
11
|
+
static targetClass = tr.TranslationKeyVersion;
|
|
12
|
+
|
|
13
|
+
@objectProperty({ path: tr.ofApplication, maxCount: 1 })
|
|
14
|
+
get ofApplication(): string {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
@objectProperty({ path: tr.ofKey, shape: TranslationKey, maxCount: 1 })
|
|
19
|
+
get ofKey(): TranslationKey {
|
|
20
|
+
return undefined as any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Monotonic ULID for new versions; deterministic `backfill-*` for migration. */
|
|
24
|
+
@literalProperty({ path: tr.versionId, maxCount: 1 })
|
|
25
|
+
get versionId(): string {
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@literalProperty({ path: tr.sourceLanguage, maxCount: 1 })
|
|
30
|
+
get sourceLanguage(): string {
|
|
31
|
+
return '';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@literalProperty({ path: tr.sourceText, maxCount: 1 })
|
|
35
|
+
get sourceText(): string {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
@literalProperty({ path: tr.format, maxCount: 1 })
|
|
40
|
+
get format(): string {
|
|
41
|
+
return 'simple';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@literalProperty({ path: tr.argumentSignature, maxCount: 1 })
|
|
45
|
+
get argumentSignature(): string {
|
|
46
|
+
return '[]';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@literalProperty({ path: tr.contractHash, maxCount: 1 })
|
|
50
|
+
get contractHash(): string {
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@literalProperty({ path: tr.sourceHash, maxCount: 1 })
|
|
55
|
+
get sourceHash(): string {
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@objectProperty({
|
|
60
|
+
path: tr.supersedes,
|
|
61
|
+
shape: TranslationKeyVersion,
|
|
62
|
+
maxCount: 1,
|
|
63
|
+
})
|
|
64
|
+
get supersedes(): TranslationKeyVersion {
|
|
65
|
+
return undefined as any;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@literalProperty({ path: tr.createdAt, datatype: xsd.dateTime, maxCount: 1 })
|
|
69
|
+
get createdAt(): Date {
|
|
70
|
+
return new Date(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@objectProperty({ path: tr.createdBy, maxCount: 1 })
|
|
74
|
+
get createdBy(): string {
|
|
75
|
+
return '';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Shape } from '@_linked/core/shapes/Shape';
|
|
2
|
+
import { literalProperty, objectProperty } from '@_linked/core/shapes/SHACL';
|
|
3
|
+
import { linkedShape } from '../package.js';
|
|
4
|
+
import { tr } from '../ontologies/translation.js';
|
|
5
|
+
|
|
6
|
+
/** App language configuration. Hosts choose the explicit control-plane store. */
|
|
7
|
+
@linkedShape
|
|
8
|
+
export class TranslationLanguage extends Shape {
|
|
9
|
+
static targetClass = tr.TranslationLanguage;
|
|
10
|
+
|
|
11
|
+
@objectProperty({ path: tr.ofApplication, maxCount: 1 })
|
|
12
|
+
get ofApplication(): string {
|
|
13
|
+
return '';
|
|
14
|
+
}
|
|
15
|
+
@objectProperty({ path: tr.languageIdentifier, maxCount: 1 })
|
|
16
|
+
get identifier(): string {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
@literalProperty({ path: tr.languageCode, maxCount: 1 })
|
|
20
|
+
get code(): string {
|
|
21
|
+
return '';
|
|
22
|
+
}
|
|
23
|
+
@literalProperty({ path: tr.nativeName, maxCount: 1 })
|
|
24
|
+
get nativeName(): string {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
@literalProperty({ path: tr.englishName, maxCount: 1 })
|
|
28
|
+
get englishName(): string {
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
@literalProperty({ path: tr.textDirection, maxCount: 1 })
|
|
32
|
+
get direction(): string {
|
|
33
|
+
return 'ltr';
|
|
34
|
+
}
|
|
35
|
+
@objectProperty({ path: tr.parentLanguage, maxCount: 1 })
|
|
36
|
+
get parent(): string {
|
|
37
|
+
return '';
|
|
38
|
+
}
|
|
39
|
+
@objectProperty({ path: tr.fallbackLanguage, maxCount: 1 })
|
|
40
|
+
get fallback(): string {
|
|
41
|
+
return '';
|
|
42
|
+
}
|
|
43
|
+
@literalProperty({ path: tr.languageEnabled, maxCount: 1 })
|
|
44
|
+
get enabled(): boolean {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
@literalProperty({ path: tr.languageSupported, maxCount: 1 })
|
|
48
|
+
get supported(): boolean {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|