lightnet 4.0.8 → 4.1.1
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 +29 -0
- package/exports/content.ts +5 -7
- package/package.json +11 -11
- package/src/astro-integration/config.ts +15 -25
- package/src/components/CategoriesSection.astro +2 -2
- package/src/components/MediaGallerySection.astro +4 -9
- package/src/components/MediaList.astro +13 -13
- package/src/components/VideoPlayer.astro +4 -4
- package/src/content/content-schema.ts +5 -292
- package/src/content/get-categories.ts +26 -29
- package/src/content/get-languages.ts +13 -26
- package/src/content/get-media-collections.ts +1 -1
- package/src/content/get-media-items.ts +1 -1
- package/src/content/get-media-types.ts +21 -14
- package/src/content/query-media-items.ts +2 -1
- package/src/content/schema/category.ts +40 -0
- package/src/content/schema/media-collection.ts +31 -0
- package/src/content/schema/media-item.ts +137 -0
- package/src/content/schema/media-type.ts +90 -0
- package/src/i18n/locals.d.ts +22 -0
- package/src/i18n/locals.ts +3 -1
- package/src/i18n/record-translation.ts +74 -0
- package/src/i18n/resolve-language.ts +12 -5
- package/src/i18n/translate-map.ts +129 -19
- package/src/i18n/translate.ts +38 -0
- package/src/i18n/translation-map-schema.ts +17 -0
- package/src/i18n/translations/TRANSLATION-STATUS.md +13 -41
- package/src/i18n/translations/ar.yml +1 -0
- package/src/i18n/translations/bn.yml +1 -0
- package/src/i18n/translations/de.yml +1 -0
- package/src/i18n/translations/en.yml +24 -21
- package/src/i18n/translations/es.yml +1 -0
- package/src/i18n/translations/fi.yml +1 -0
- package/src/i18n/translations/fr.yml +1 -0
- package/src/i18n/translations/hi.yml +1 -0
- package/src/i18n/translations/kk.yml +3 -0
- package/src/i18n/translations/pt.yml +1 -0
- package/src/i18n/translations/ru.yml +1 -0
- package/src/i18n/translations/uk.yml +1 -0
- package/src/i18n/translations/ur.yml +1 -0
- package/src/i18n/translations/zh.yml +1 -0
- package/src/i18n/translations.ts +5 -2
- package/src/layouts/Page.astro +3 -4
- package/src/layouts/components/Footer.astro +63 -10
- package/src/layouts/components/LanguagePicker.astro +2 -2
- package/src/layouts/components/MenuItem.astro +4 -4
- package/src/layouts/components/PageNavigation.astro +21 -29
- package/src/layouts/components/PageTitle.astro +4 -13
- package/src/pages/details-page/DefaultDetailsPage.astro +2 -15
- package/src/pages/details-page/components/AudioPanel.astro +5 -4
- package/src/pages/details-page/components/AudioPlayer.astro +4 -4
- package/src/pages/details-page/components/ContentSection.astro +42 -43
- package/src/pages/details-page/components/MediaCollection.astro +2 -6
- package/src/pages/details-page/components/main-details/OpenButton.astro +25 -19
- package/src/pages/details-page/components/main-details/ShareButton.astro +1 -1
- package/src/pages/details-page/components/more-details/Categories.astro +3 -5
- package/src/pages/details-page/components/more-details/Languages.astro +7 -3
- package/src/pages/details-page/utils/create-content-metadata.ts +40 -56
- package/src/pages/search-page/api/search.ts +1 -1
- package/src/pages/search-page/components/SearchFilter.astro +5 -5
- package/src/pages/search-page/components/SearchList.astro +22 -19
- package/src/utils/is-external-url.ts +34 -0
- package/src/utils/link-attributes.ts +10 -0
- package/src/utils/paths.ts +6 -0
- package/src/utils/urls.ts +12 -24
- package/src/astro-integration/validators/validate-inline-translations.ts +0 -51
|
@@ -2,7 +2,7 @@ import { AstroError } from "astro/errors"
|
|
|
2
2
|
import i18next from "i18next"
|
|
3
3
|
import config from "virtual:lightnet/config"
|
|
4
4
|
|
|
5
|
-
import type {
|
|
5
|
+
import type { TranslateConfigFieldFn } from "./translate-map"
|
|
6
6
|
|
|
7
7
|
const languages = Object.fromEntries(
|
|
8
8
|
config.languages.map((language) => [language.code, language]),
|
|
@@ -25,13 +25,20 @@ export const resolveLanguage = (bcp47: string) => {
|
|
|
25
25
|
|
|
26
26
|
export const resolveTranslatedLanguage = (
|
|
27
27
|
bcp47: string,
|
|
28
|
-
|
|
28
|
+
tConfigField: TranslateConfigFieldFn,
|
|
29
29
|
) => {
|
|
30
30
|
const language = resolveLanguage(bcp47)
|
|
31
31
|
return {
|
|
32
32
|
...language,
|
|
33
|
-
labelText:
|
|
34
|
-
path: ["languages", bcp47, "label"],
|
|
35
|
-
}),
|
|
33
|
+
labelText: tConfigField(language.label, config),
|
|
36
34
|
}
|
|
37
35
|
}
|
|
36
|
+
|
|
37
|
+
export async function getTranslatedLanguages(
|
|
38
|
+
currentLocale: string,
|
|
39
|
+
tConfigField: TranslateConfigFieldFn,
|
|
40
|
+
) {
|
|
41
|
+
return config.languages
|
|
42
|
+
.map(({ code }) => resolveTranslatedLanguage(code, tConfigField))
|
|
43
|
+
.sort((a, b) => a.labelText.localeCompare(b.labelText, currentLocale))
|
|
44
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { AstroError } from "astro/errors"
|
|
2
|
+
import type { CollectionKey } from "astro:content"
|
|
2
3
|
import config from "virtual:lightnet/config"
|
|
3
4
|
|
|
5
|
+
import type { ExtendedLightnetConfig } from "../astro-integration/config"
|
|
6
|
+
import { recordTranslation } from "./record-translation"
|
|
7
|
+
|
|
4
8
|
/**
|
|
5
9
|
* A map of translated values keyed by locale code.
|
|
6
10
|
*
|
|
@@ -12,14 +16,6 @@ import config from "virtual:lightnet/config"
|
|
|
12
16
|
*/
|
|
13
17
|
export type TranslationMap = Record<string, string | undefined>
|
|
14
18
|
|
|
15
|
-
/**
|
|
16
|
-
* Describes where a translation map comes from so missing-value
|
|
17
|
-
* errors can point to the exact field in config or content.
|
|
18
|
-
*/
|
|
19
|
-
export type TranslationMapContext = {
|
|
20
|
-
path: (string | number)[]
|
|
21
|
-
}
|
|
22
|
-
|
|
23
19
|
/**
|
|
24
20
|
* Resolve a translation map for the current locale, falling back
|
|
25
21
|
* to configured default locale when needed.
|
|
@@ -32,7 +28,37 @@ export type TranslationMapContext = {
|
|
|
32
28
|
*/
|
|
33
29
|
export type TranslateMapFn = (
|
|
34
30
|
translationMap: TranslationMap,
|
|
35
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Describes where a translation map comes from so translation logs
|
|
33
|
+
* can point to the exact field in config or content.
|
|
34
|
+
*/
|
|
35
|
+
context: { path: (string | number)[] },
|
|
36
|
+
) => string
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Resolve an inline translation map that belongs to a content entry.
|
|
40
|
+
*
|
|
41
|
+
* The entry is only used to provide a stable fallback path when translation-map
|
|
42
|
+
* metadata is missing during the current refactor.
|
|
43
|
+
*/
|
|
44
|
+
export type TranslateContentFieldFn = (
|
|
45
|
+
translationMap: TranslationMap,
|
|
46
|
+
contentEntry: {
|
|
47
|
+
id: string
|
|
48
|
+
collection: CollectionKey
|
|
49
|
+
data: Record<PropertyKey, unknown>
|
|
50
|
+
},
|
|
51
|
+
) => string
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Resolve an inline translation map that belongs to the LightNet config.
|
|
55
|
+
*
|
|
56
|
+
* The config object is only used to keep the API explicit and to provide a
|
|
57
|
+
* stable fallback path when translation-map metadata is missing.
|
|
58
|
+
*/
|
|
59
|
+
export type TranslateConfigFieldFn = (
|
|
60
|
+
translationMap: TranslationMap,
|
|
61
|
+
config: ExtendedLightnetConfig,
|
|
36
62
|
) => string
|
|
37
63
|
|
|
38
64
|
/**
|
|
@@ -45,26 +71,110 @@ export type TranslateMapFn = (
|
|
|
45
71
|
* @param currentLocale The locale that should be resolved first before
|
|
46
72
|
* falling back to LightNet's configured default locale.
|
|
47
73
|
*/
|
|
48
|
-
export function useTranslateMap(currentLocale: string)
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
74
|
+
export function useTranslateMap(currentLocale: string) {
|
|
75
|
+
const tMap: TranslateMapFn = (translationMap, context) => {
|
|
76
|
+
const getKey = () => {
|
|
77
|
+
const keyCacheSymbol = Symbol.for("ln.key-cache")
|
|
78
|
+
if (hasOwnProperty(translationMap, keyCacheSymbol)) {
|
|
79
|
+
return translationMap[keyCacheSymbol] as string
|
|
80
|
+
}
|
|
81
|
+
const value = context.path.join(".")
|
|
82
|
+
Object.defineProperty(translationMap, keyCacheSymbol, { value })
|
|
83
|
+
return value
|
|
84
|
+
}
|
|
85
|
+
const key = getKey()
|
|
86
|
+
recordTranslation({ key, values: translationMap, type: "map" })
|
|
87
|
+
|
|
88
|
+
const currentLocaleTranslation = translationMap[currentLocale]
|
|
89
|
+
if (currentLocaleTranslation) {
|
|
90
|
+
return currentLocaleTranslation
|
|
53
91
|
}
|
|
54
92
|
|
|
55
|
-
const
|
|
56
|
-
if (
|
|
57
|
-
return
|
|
93
|
+
const defaultLocaleTranslation = translationMap[config.defaultLocale]
|
|
94
|
+
if (defaultLocaleTranslation) {
|
|
95
|
+
return defaultLocaleTranslation
|
|
58
96
|
}
|
|
59
97
|
|
|
60
|
-
const availableLocales = Object.keys(translationMap)
|
|
98
|
+
const availableLocales = Object.keys(translationMap).filter(
|
|
99
|
+
(key) => key !== "path",
|
|
100
|
+
)
|
|
61
101
|
const availableLocalesText = availableLocales.length
|
|
62
102
|
? availableLocales.map((locale) => `"${locale}"`).join(", ")
|
|
63
103
|
: "none"
|
|
64
104
|
|
|
65
105
|
throw new AstroError(
|
|
66
|
-
`Missing translation map value for "${
|
|
106
|
+
`Missing translation map value for "${key}" in locales "${currentLocale}" and "${config.defaultLocale}"`,
|
|
67
107
|
`Available locales: ${availableLocalesText}. Add a value for "${currentLocale}" or "${config.defaultLocale}" to this inline translation map.`,
|
|
68
108
|
)
|
|
69
109
|
}
|
|
110
|
+
|
|
111
|
+
const tContentField: TranslateContentFieldFn = (
|
|
112
|
+
translationMap,
|
|
113
|
+
contentEntry,
|
|
114
|
+
) => {
|
|
115
|
+
return tMap(translationMap, {
|
|
116
|
+
path: getMapPath(translationMap, contentEntry.data, [
|
|
117
|
+
"content",
|
|
118
|
+
contentEntry.collection,
|
|
119
|
+
contentEntry.id,
|
|
120
|
+
]),
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const tConfigField: TranslateConfigFieldFn = (translationMap, _config) => {
|
|
125
|
+
return tMap(translationMap, {
|
|
126
|
+
path: getMapPath(translationMap, _config, ["config"]),
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return { tMap, tContentField, tConfigField }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function getMapPath(
|
|
134
|
+
translationMap: TranslationMap,
|
|
135
|
+
data: unknown,
|
|
136
|
+
path: string[],
|
|
137
|
+
) {
|
|
138
|
+
const pathCacheSymbol = Symbol.for("ln.path-cache")
|
|
139
|
+
|
|
140
|
+
if (hasOwnProperty(translationMap, pathCacheSymbol)) {
|
|
141
|
+
return translationMap[pathCacheSymbol] as string[]
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const findPath: (_data: unknown, _path: string[]) => string[] | undefined = (
|
|
145
|
+
_data,
|
|
146
|
+
_path,
|
|
147
|
+
) => {
|
|
148
|
+
if (!_data || typeof _data !== "object") {
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
if (_data === translationMap) {
|
|
152
|
+
return _path
|
|
153
|
+
}
|
|
154
|
+
for (const [key, value] of Object.entries(_data)) {
|
|
155
|
+
const p = findPath(value, [..._path, key])
|
|
156
|
+
if (p) {
|
|
157
|
+
return p as string[]
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const resolvedPath = findPath(data, path)
|
|
163
|
+
if (!resolvedPath) {
|
|
164
|
+
throw new AstroError(
|
|
165
|
+
`Invalid map context provided ${path} for could not find path for object ${JSON.stringify(translationMap)}`,
|
|
166
|
+
`Provided object ${JSON.stringify(data)}`,
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
Object.defineProperty(translationMap, pathCacheSymbol, {
|
|
170
|
+
value: resolvedPath,
|
|
171
|
+
})
|
|
172
|
+
return resolvedPath
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function hasOwnProperty<K extends PropertyKey>(
|
|
176
|
+
obj: unknown,
|
|
177
|
+
key: K,
|
|
178
|
+
): obj is Record<K, unknown> {
|
|
179
|
+
return !!obj && typeof obj === "object" && Object.hasOwn(obj, key)
|
|
70
180
|
}
|
package/src/i18n/translate.ts
CHANGED
|
@@ -3,6 +3,7 @@ import i18next, { type TOptions } from "i18next"
|
|
|
3
3
|
import config from "virtual:lightnet/config"
|
|
4
4
|
|
|
5
5
|
import { lazy } from "../utils/lazy"
|
|
6
|
+
import { recordTranslation } from "./record-translation"
|
|
6
7
|
import { type LightNetTranslationKey, loadTranslations } from "./translations"
|
|
7
8
|
|
|
8
9
|
// We add (string & NonNullable<unknown>) to preserve typescript autocompletion for known keys
|
|
@@ -68,6 +69,7 @@ export async function useTranslate(
|
|
|
68
69
|
const resolvedLocale = bcp47 ?? config.defaultLocale
|
|
69
70
|
const translations = await i18nextTranslations.get()
|
|
70
71
|
const availableTranslationKeys = new Set(await translationKeys.get())
|
|
72
|
+
recordAllTranslations()
|
|
71
73
|
|
|
72
74
|
const i18n = i18next.createInstance()
|
|
73
75
|
|
|
@@ -100,3 +102,39 @@ export async function useTranslate(
|
|
|
100
102
|
return value
|
|
101
103
|
}
|
|
102
104
|
}
|
|
105
|
+
|
|
106
|
+
async function recordAllTranslations() {
|
|
107
|
+
if (!import.meta.env.PROD) {
|
|
108
|
+
// only record translations during build time
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const { locales } = config
|
|
113
|
+
const localesIncludingEnglish = [...locales.filter((l) => l !== "en"), "en"]
|
|
114
|
+
const keys = await translationKeys.get()
|
|
115
|
+
const translations = await i18nextTranslations.get()
|
|
116
|
+
|
|
117
|
+
const collectValues = (key: string, locales: string[]) => {
|
|
118
|
+
const values = {} as Record<string, string | undefined>
|
|
119
|
+
for (const locale of locales) {
|
|
120
|
+
values[locale] = translations[locale]?.translation[key]
|
|
121
|
+
}
|
|
122
|
+
return values
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (const key of keys) {
|
|
126
|
+
if (key.startsWith("ln.")) {
|
|
127
|
+
recordTranslation({
|
|
128
|
+
key,
|
|
129
|
+
values: collectValues(key, localesIncludingEnglish),
|
|
130
|
+
type: "lightnet",
|
|
131
|
+
})
|
|
132
|
+
} else {
|
|
133
|
+
recordTranslation({
|
|
134
|
+
key,
|
|
135
|
+
values: collectValues(key, locales),
|
|
136
|
+
type: "user",
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { z } from "astro/zod"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Translations by BCP-47 tag
|
|
5
|
+
* Must contain at least one localized value.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* {
|
|
9
|
+
* de: "Hallo",
|
|
10
|
+
* en: "Hello"
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
export const translationMapSchema = z
|
|
14
|
+
.record(z.string(), z.string().nonempty())
|
|
15
|
+
.refine((value) => Object.keys(value).length > 0, {
|
|
16
|
+
message: "Inline translations must contain at least one entry",
|
|
17
|
+
})
|
|
@@ -4,21 +4,15 @@ This autogenerated report shows all built-in languages and the current status of
|
|
|
4
4
|
|
|
5
5
|
## **AR** ([ar.yml](./ar.yml))
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- ln.details.edit
|
|
7
|
+
All keys have been translated. ✅
|
|
10
8
|
|
|
11
9
|
## **BN** ([bn.yml](./bn.yml))
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- ln.details.edit
|
|
11
|
+
All keys have been translated. ✅
|
|
16
12
|
|
|
17
13
|
## **DE** ([de.yml](./de.yml))
|
|
18
14
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- ln.details.edit
|
|
15
|
+
All keys have been translated. ✅
|
|
22
16
|
|
|
23
17
|
## **EN** ([en.yml](./en.yml))
|
|
24
18
|
|
|
@@ -26,62 +20,40 @@ All keys have been translated. ✅
|
|
|
26
20
|
|
|
27
21
|
## **ES** ([es.yml](./es.yml))
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
- ln.details.edit
|
|
23
|
+
All keys have been translated. ✅
|
|
32
24
|
|
|
33
25
|
## **FI** ([fi.yml](./fi.yml))
|
|
34
26
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
- ln.details.edit
|
|
27
|
+
All keys have been translated. ✅
|
|
38
28
|
|
|
39
29
|
## **FR** ([fr.yml](./fr.yml))
|
|
40
30
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
- ln.details.edit
|
|
31
|
+
All keys have been translated. ✅
|
|
44
32
|
|
|
45
33
|
## **HI** ([hi.yml](./hi.yml))
|
|
46
34
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
- ln.details.edit
|
|
35
|
+
All keys have been translated. ✅
|
|
50
36
|
|
|
51
37
|
## **KK** ([kk.yml](./kk.yml))
|
|
52
38
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- ln.previous
|
|
56
|
-
- ln.next
|
|
57
|
-
- ln.details.edit
|
|
39
|
+
All keys have been translated. ✅
|
|
58
40
|
|
|
59
41
|
## **PT** ([pt.yml](./pt.yml))
|
|
60
42
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
- ln.details.edit
|
|
43
|
+
All keys have been translated. ✅
|
|
64
44
|
|
|
65
45
|
## **RU** ([ru.yml](./ru.yml))
|
|
66
46
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- ln.details.edit
|
|
47
|
+
All keys have been translated. ✅
|
|
70
48
|
|
|
71
49
|
## **UK** ([uk.yml](./uk.yml))
|
|
72
50
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
- ln.details.edit
|
|
51
|
+
All keys have been translated. ✅
|
|
76
52
|
|
|
77
53
|
## **UR** ([ur.yml](./ur.yml))
|
|
78
54
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
- ln.details.edit
|
|
55
|
+
All keys have been translated. ✅
|
|
82
56
|
|
|
83
57
|
## **ZH** ([zh.yml](./zh.yml))
|
|
84
58
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
- ln.details.edit
|
|
59
|
+
All keys have been translated. ✅
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: جميع الفئات
|
|
|
17
17
|
ln.search.no-results: لا توجد نتائج
|
|
18
18
|
ln.details.open: فتح
|
|
19
19
|
ln.details.share: مشاركة
|
|
20
|
+
ln.details.edit: تحرير
|
|
20
21
|
ln.details.part-of-collection: جزء من مجموعة
|
|
21
22
|
ln.details.download: تنزيل
|
|
22
23
|
ln.share.url-copied-to-clipboard: تم نسخ الرابط إلى الحافظة
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: সকল বিভাগ
|
|
|
17
17
|
ln.search.no-results: কোনো ফলাফল নেই
|
|
18
18
|
ln.details.open: খুলুন
|
|
19
19
|
ln.details.share: শেয়ার করুন
|
|
20
|
+
ln.details.edit: সম্পাদনা করুন
|
|
20
21
|
ln.details.part-of-collection: সংগ্রহের অংশ
|
|
21
22
|
ln.details.download: ডাউনলোড করুন
|
|
22
23
|
ln.share.url-copied-to-clipboard: লিঙ্ক ক্লিপবোর্ডে কপি হয়েছে
|
|
@@ -11,6 +11,7 @@ ln.external-link: Externer Link
|
|
|
11
11
|
ln.details.open: Öffnen
|
|
12
12
|
ln.details.part-of-collection: Teil der Sammlung
|
|
13
13
|
ln.details.download: Download
|
|
14
|
+
ln.details.edit: Bearbeiten
|
|
14
15
|
ln.details.share: Teilen
|
|
15
16
|
ln.header.open-main-menu: Öffne Hauptmenü
|
|
16
17
|
ln.header.select-language: Sprache auswählen
|
|
@@ -2,104 +2,106 @@
|
|
|
2
2
|
# This is only "visible" to a screen-reader.
|
|
3
3
|
#
|
|
4
4
|
# English: Open main menu
|
|
5
|
-
# Used on: https://
|
|
5
|
+
# Used on: https://kuuluu.org/en (not visible)
|
|
6
6
|
ln.header.open-main-menu: Open main menu
|
|
7
7
|
|
|
8
8
|
# Accessibility label for the language menu.
|
|
9
9
|
# This is only "visible" to a screen-reader.
|
|
10
10
|
#
|
|
11
11
|
# English: Select language
|
|
12
|
-
# Used on: https://
|
|
12
|
+
# Used on: https://kuuluu.org/en (not visible)
|
|
13
13
|
ln.header.select-language: Select language
|
|
14
14
|
|
|
15
15
|
# Display name for the home page.
|
|
16
16
|
#
|
|
17
17
|
# English: Home
|
|
18
|
-
# Used on: https://
|
|
18
|
+
# Used on: https://kuuluu.org/en (first item in the main menu)
|
|
19
19
|
ln.home.title: Home
|
|
20
20
|
|
|
21
21
|
# Label for a single media item category.
|
|
22
22
|
#
|
|
23
23
|
# English: Category
|
|
24
|
-
# Used on: https://
|
|
24
|
+
# Used on: https://kuuluu.org/en/media
|
|
25
25
|
ln.category: Category
|
|
26
26
|
|
|
27
27
|
# Label for multiple media item categories.
|
|
28
28
|
#
|
|
29
29
|
# English: Categories
|
|
30
|
-
# Used on: https://
|
|
30
|
+
# Used on: https://kuuluu.org/en/media/how-to-360-flip--en/
|
|
31
31
|
ln.categories: Categories
|
|
32
32
|
|
|
33
33
|
# Label for a single language.
|
|
34
34
|
#
|
|
35
35
|
# English: Language
|
|
36
|
-
# Used on: https://
|
|
36
|
+
# Used on: https://kuuluu.org/en/media
|
|
37
37
|
ln.language: Language
|
|
38
38
|
|
|
39
39
|
# Label for multiple languages.
|
|
40
40
|
#
|
|
41
41
|
# English: Languages
|
|
42
|
-
# Used on: https://
|
|
42
|
+
# Used on: https://kuuluu.org/en/media/how-to-kickflip--en/
|
|
43
43
|
ln.languages: Languages
|
|
44
44
|
|
|
45
45
|
# Label for a single media type.
|
|
46
46
|
#
|
|
47
47
|
# English: Type
|
|
48
|
-
# Used on: https://
|
|
48
|
+
# Used on: https://kuuluu.org/en/media
|
|
49
49
|
ln.type: Type
|
|
50
50
|
|
|
51
51
|
# Accessibility label for buttons to show the previous items.
|
|
52
52
|
# This is used on the carousel arrow button.
|
|
53
53
|
#
|
|
54
54
|
# English: Previous
|
|
55
|
+
# Used on: https://kuuluu.org/en (not visible)
|
|
55
56
|
ln.previous: Previous
|
|
56
57
|
|
|
57
58
|
# Accessibility label for buttons to show the next items.
|
|
58
59
|
# This is used on the carousel arrow button.
|
|
59
60
|
#
|
|
60
61
|
# English: Next
|
|
62
|
+
# Used on: https://kuuluu.org/en (not visible)
|
|
61
63
|
ln.next: Next
|
|
62
64
|
|
|
63
65
|
# Hint for an external link.
|
|
64
66
|
#
|
|
65
67
|
# English: External link - opens in a new tab
|
|
66
|
-
# Used on: https://
|
|
68
|
+
# Used on: https://kuuluu.org/en/media/ollie-with-integrity--en/
|
|
67
69
|
ln.external-link: External link - opens in a new tab
|
|
68
70
|
|
|
69
71
|
# Title for the search page.
|
|
70
72
|
#
|
|
71
73
|
# English: Search
|
|
72
|
-
# Used on: https://
|
|
74
|
+
# Used on: https://kuuluu.org/en/media/ (not visible)
|
|
73
75
|
ln.search.title: Search
|
|
74
76
|
|
|
75
77
|
# Placeholder text for the search input to search for media items.
|
|
76
78
|
# English: Search media
|
|
77
79
|
#
|
|
78
|
-
# Used on: https://
|
|
80
|
+
# Used on: https://kuuluu.org/en/media/
|
|
79
81
|
ln.search.placeholder: Search media
|
|
80
82
|
|
|
81
83
|
# Filter option to display content in all languages.
|
|
82
84
|
#
|
|
83
85
|
# English: All languages
|
|
84
|
-
# Used on: https://
|
|
86
|
+
# Used on: https://kuuluu.org/en/media/
|
|
85
87
|
ln.search.all-languages: All languages
|
|
86
88
|
|
|
87
89
|
# Filter option to display all media types.
|
|
88
90
|
#
|
|
89
91
|
# English: All types
|
|
90
|
-
# Used on: https://
|
|
92
|
+
# Used on: https://kuuluu.org/en/media/
|
|
91
93
|
ln.search.all-types: All types
|
|
92
94
|
|
|
93
95
|
# Filter option to display all media item categories.
|
|
94
96
|
#
|
|
95
97
|
# English: All categories
|
|
96
|
-
# Used on: https://
|
|
98
|
+
# Used on: https://kuuluu.org/en/media/
|
|
97
99
|
ln.search.all-categories: All categories
|
|
98
100
|
|
|
99
101
|
# Message displayed when no search results are found.
|
|
100
102
|
#
|
|
101
103
|
# English: No results
|
|
102
|
-
# Used on: https://
|
|
104
|
+
# Used on: https://kuuluu.org/en/media/?language=de&type=book
|
|
103
105
|
ln.search.no-results: No results
|
|
104
106
|
|
|
105
107
|
# Button label to open a media item's main content.
|
|
@@ -110,7 +112,7 @@ ln.details.open: Open
|
|
|
110
112
|
# Button label to share a media item.
|
|
111
113
|
#
|
|
112
114
|
# English: Share
|
|
113
|
-
# Used on: https://
|
|
115
|
+
# Used on: https://kuuluu.org/en/media/ollie-with-integrity--en/
|
|
114
116
|
ln.details.share: Share
|
|
115
117
|
|
|
116
118
|
# Button label to start editing an item
|
|
@@ -121,32 +123,33 @@ ln.details.edit: Edit
|
|
|
121
123
|
# Label for indicating that the media item belongs to a collection.
|
|
122
124
|
#
|
|
123
125
|
# English: Part of collection
|
|
124
|
-
# Used on: https://
|
|
126
|
+
# Used on: https://kuuluu.org/en/media/ollie-with-integrity--en/
|
|
125
127
|
ln.details.part-of-collection: Part of collection
|
|
126
128
|
|
|
127
129
|
# Button label for downloading a media item.
|
|
128
130
|
#
|
|
129
131
|
# English: Download
|
|
130
|
-
# Used on: https://
|
|
132
|
+
# Used on: https://kuuluu.org/en/media/ride-the-ramp-of-faith--en/
|
|
131
133
|
ln.details.download: Download
|
|
132
134
|
|
|
133
135
|
# Notification message indicating that the link has been copied to the clipboard.
|
|
134
136
|
#
|
|
135
137
|
# English: Link copied to clipboard
|
|
136
|
-
# Used on: https://
|
|
138
|
+
# Used on: https://kuuluu.org/en/media/ride-the-ramp-of-faith--en/ (Firefox)
|
|
137
139
|
ln.share.url-copied-to-clipboard: Link copied to clipboard
|
|
138
140
|
|
|
139
141
|
# Title for the 404-error page. This page is displayed when a path does not exist.
|
|
140
142
|
#
|
|
141
143
|
# English: Page not found
|
|
142
|
-
# Used on: https://
|
|
144
|
+
# Used on: https://kuuluu.org/unexisting-path
|
|
143
145
|
ln.404.page-not-found: Page not found
|
|
144
146
|
|
|
145
147
|
# Button label on the 404-error page for returning to the home page.
|
|
146
148
|
#
|
|
147
149
|
# English: Go to Home page
|
|
148
|
-
# Used on: https://
|
|
150
|
+
# Used on: https://kuuluu.org/unexisting-path
|
|
149
151
|
ln.404.go-to-the-home-page: Go to Home page
|
|
150
152
|
|
|
151
153
|
# Footer text to give credits to LightNet
|
|
154
|
+
# Used on: https://kuuluu.org/en
|
|
152
155
|
ln.footer.powered-by-lightnet: Powered by LightNet
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: Todas las categorías
|
|
|
17
17
|
ln.search.no-results: Sin resultados
|
|
18
18
|
ln.details.open: Abrir
|
|
19
19
|
ln.details.share: Compartir
|
|
20
|
+
ln.details.edit: Editar
|
|
20
21
|
ln.details.part-of-collection: Parte de la colección
|
|
21
22
|
ln.details.download: Descargar
|
|
22
23
|
ln.share.url-copied-to-clipboard: Enlace copiado al portapapeles
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: Kaikki kategoriat
|
|
|
17
17
|
ln.search.no-results: Ei tuloksia
|
|
18
18
|
ln.details.open: Avaa
|
|
19
19
|
ln.details.share: Jaa
|
|
20
|
+
ln.details.edit: Muokkaa
|
|
20
21
|
ln.details.part-of-collection: Osa kokoelmaa
|
|
21
22
|
ln.details.download: Lataa
|
|
22
23
|
ln.share.url-copied-to-clipboard: Linkki kopioitu leikepöydälle
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: Toutes les catégories
|
|
|
17
17
|
ln.search.no-results: Aucun résultat
|
|
18
18
|
ln.details.open: Ouvrir
|
|
19
19
|
ln.details.share: Partager
|
|
20
|
+
ln.details.edit: Modifier
|
|
20
21
|
ln.details.part-of-collection: Fait partie de la collection
|
|
21
22
|
ln.details.download: Télécharger
|
|
22
23
|
ln.share.url-copied-to-clipboard: Lien copié dans le presse-papiers
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: सभी श्रेणियाँ
|
|
|
17
17
|
ln.search.no-results: कोई परिणाम नहीं मिला
|
|
18
18
|
ln.details.open: खोलें
|
|
19
19
|
ln.details.share: साझा करें
|
|
20
|
+
ln.details.edit: संपादित करें
|
|
20
21
|
ln.details.part-of-collection: संग्रह का भाग
|
|
21
22
|
ln.details.download: डाउनलोड करें
|
|
22
23
|
ln.share.url-copied-to-clipboard: लिंक क्लिपबोर्ड पर कॉपी हो गया है
|
|
@@ -6,6 +6,8 @@ ln.categories: Барлық санаттар
|
|
|
6
6
|
ln.language: Тіл
|
|
7
7
|
ln.languages: Тілдер
|
|
8
8
|
ln.type: Түрі
|
|
9
|
+
ln.previous: Алдыңғы
|
|
10
|
+
ln.next: Келесі
|
|
9
11
|
ln.external-link: Сыртқы сілтеме
|
|
10
12
|
ln.search.title: Іздеу
|
|
11
13
|
ln.search.placeholder: Медиа іздеу
|
|
@@ -15,6 +17,7 @@ ln.search.all-categories: Барлық санаттар
|
|
|
15
17
|
ln.search.no-results: Нәтижие жоқ
|
|
16
18
|
ln.details.open: Ашу
|
|
17
19
|
ln.details.share: Бөлісу
|
|
20
|
+
ln.details.edit: Өңдеу
|
|
18
21
|
ln.details.part-of-collection: Жинақ бөлімі
|
|
19
22
|
ln.details.download: Жүктеу
|
|
20
23
|
ln.share.url-copied-to-clipboard: Жүктеме көшірілді
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: Todas as categorias
|
|
|
17
17
|
ln.search.no-results: Nenhum resultado
|
|
18
18
|
ln.details.open: Abrir
|
|
19
19
|
ln.details.share: Partilhar
|
|
20
|
+
ln.details.edit: Editar
|
|
20
21
|
ln.details.part-of-collection: Parte da coleção
|
|
21
22
|
ln.details.download: Transferir
|
|
22
23
|
ln.share.url-copied-to-clipboard: Ligação copiada para a área de transferência
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: Все категории
|
|
|
17
17
|
ln.search.no-results: Нет результатов
|
|
18
18
|
ln.details.open: Открыть
|
|
19
19
|
ln.details.share: Поделиться
|
|
20
|
+
ln.details.edit: Редактировать
|
|
20
21
|
ln.details.part-of-collection: Часть коллекции
|
|
21
22
|
ln.details.download: Скачать
|
|
22
23
|
ln.share.url-copied-to-clipboard: Ссылка скопированa в буфер
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: Усі категорії
|
|
|
17
17
|
ln.search.no-results: Немає результатів
|
|
18
18
|
ln.details.open: Відкрити
|
|
19
19
|
ln.details.share: Поділитися
|
|
20
|
+
ln.details.edit: Редагувати
|
|
20
21
|
ln.details.part-of-collection: Частина колекції
|
|
21
22
|
ln.details.download: Завантажити
|
|
22
23
|
ln.share.url-copied-to-clipboard: Посилання скопійовано до буферу обміну
|
|
@@ -17,6 +17,7 @@ ln.search.all-categories: تمام زمرے
|
|
|
17
17
|
ln.search.no-results: کوئی نتیجہ نہیں ملا
|
|
18
18
|
ln.details.open: کھولیں
|
|
19
19
|
ln.details.share: شیئر کریں
|
|
20
|
+
ln.details.edit: ترمیم کریں
|
|
20
21
|
ln.details.part-of-collection: مجموعے کا حصہ
|
|
21
22
|
ln.details.download: ڈاؤن لوڈ کریں
|
|
22
23
|
ln.share.url-copied-to-clipboard: لنک کاپی ہو گیا
|