@secorto/i18n 0.0.4
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 +12 -0
- package/dist/index.d.mts +299 -0
- package/dist/index.mjs +304 -0
- package/package.json +59 -0
- package/src/core/extract-id.ts +39 -0
- package/src/core/index.ts +4 -0
- package/src/core/locale.ts +30 -0
- package/src/core/standalone.ts +96 -0
- package/src/core/translationLink.ts +130 -0
- package/src/index.ts +2 -0
- package/src/section/detail-path.ts +95 -0
- package/src/section/details-links.ts +42 -0
- package/src/section/entry-adapter.ts +57 -0
- package/src/section/index.ts +5 -0
- package/src/section/routes.ts +128 -0
- package/src/section/translation-index.ts +71 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a localized entry in the translation system.
|
|
3
|
+
* @template E - The type of the content (e.g., { title: string, body: string }).
|
|
4
|
+
* @template C - The section of the application (e.g., 'blog', 'docs').
|
|
5
|
+
* @template L - The language code (e.g., 'es', 'en').
|
|
6
|
+
*/
|
|
7
|
+
export interface LocalizedEntry<
|
|
8
|
+
TEntry,
|
|
9
|
+
L extends string
|
|
10
|
+
> {
|
|
11
|
+
cleanId: string
|
|
12
|
+
translationKey: string
|
|
13
|
+
locale: L
|
|
14
|
+
draft: boolean
|
|
15
|
+
original: TEntry
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Represents a translation index that groups localized entries by their translation key and locale.
|
|
20
|
+
* @template L - The type of the language code (e.g., 'es', 'en').
|
|
21
|
+
* @template E - The type of the content (e.g., { title: string, body: string }).
|
|
22
|
+
* @template C - The section of the application (e.g., 'blog', 'docs').
|
|
23
|
+
*/
|
|
24
|
+
export type TranslationIndex<
|
|
25
|
+
L extends string,
|
|
26
|
+
TEntry
|
|
27
|
+
> = Record<
|
|
28
|
+
string,
|
|
29
|
+
Partial<Record<L, LocalizedEntry<TEntry, L>>>
|
|
30
|
+
>
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Builds a translation index from an array of localized entries.
|
|
34
|
+
* The index groups entries by their translation key and locale.
|
|
35
|
+
* If duplicate entries for the same translation key and locale are found, an error is thrown.
|
|
36
|
+
* @template E - The type of the content (e.g., { title: string, body: string }).
|
|
37
|
+
* @template C - The section of the application (e.g., 'blog', 'docs').
|
|
38
|
+
* @template L - The language code (e.g., 'es', 'en').
|
|
39
|
+
* @param entries Entries to index
|
|
40
|
+
* @returns The translation index, grouped by translation key and locale
|
|
41
|
+
* @throws Error if duplicate entries for the same translation key and locale are found
|
|
42
|
+
*/
|
|
43
|
+
export function createTranslationIndex<
|
|
44
|
+
L extends string,
|
|
45
|
+
TEntry
|
|
46
|
+
>(
|
|
47
|
+
entries: readonly LocalizedEntry<TEntry, L>[]
|
|
48
|
+
): TranslationIndex<L, TEntry> {
|
|
49
|
+
// Using map to safely mutate internally without lying to TypeScript
|
|
50
|
+
const map = new Map<string, Partial<Record<L, LocalizedEntry<TEntry, L>>>>()
|
|
51
|
+
|
|
52
|
+
for (const entry of entries) {
|
|
53
|
+
const key = entry.translationKey
|
|
54
|
+
const locale = entry.locale
|
|
55
|
+
|
|
56
|
+
// Get or create the group for this key
|
|
57
|
+
let group = map.get(key)
|
|
58
|
+
if (!group) {
|
|
59
|
+
group = {}
|
|
60
|
+
map.set(key, group)
|
|
61
|
+
} else if (locale in group) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Duplicate translation for key "${key}" and locale "${locale}"`
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Assign directly to the entry
|
|
68
|
+
group[locale] = entry
|
|
69
|
+
}
|
|
70
|
+
return Object.fromEntries(map)
|
|
71
|
+
}
|