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.
Files changed (66) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/exports/content.ts +5 -7
  3. package/package.json +11 -11
  4. package/src/astro-integration/config.ts +15 -25
  5. package/src/components/CategoriesSection.astro +2 -2
  6. package/src/components/MediaGallerySection.astro +4 -9
  7. package/src/components/MediaList.astro +13 -13
  8. package/src/components/VideoPlayer.astro +4 -4
  9. package/src/content/content-schema.ts +5 -292
  10. package/src/content/get-categories.ts +26 -29
  11. package/src/content/get-languages.ts +13 -26
  12. package/src/content/get-media-collections.ts +1 -1
  13. package/src/content/get-media-items.ts +1 -1
  14. package/src/content/get-media-types.ts +21 -14
  15. package/src/content/query-media-items.ts +2 -1
  16. package/src/content/schema/category.ts +40 -0
  17. package/src/content/schema/media-collection.ts +31 -0
  18. package/src/content/schema/media-item.ts +137 -0
  19. package/src/content/schema/media-type.ts +90 -0
  20. package/src/i18n/locals.d.ts +22 -0
  21. package/src/i18n/locals.ts +3 -1
  22. package/src/i18n/record-translation.ts +74 -0
  23. package/src/i18n/resolve-language.ts +12 -5
  24. package/src/i18n/translate-map.ts +129 -19
  25. package/src/i18n/translate.ts +38 -0
  26. package/src/i18n/translation-map-schema.ts +17 -0
  27. package/src/i18n/translations/TRANSLATION-STATUS.md +13 -41
  28. package/src/i18n/translations/ar.yml +1 -0
  29. package/src/i18n/translations/bn.yml +1 -0
  30. package/src/i18n/translations/de.yml +1 -0
  31. package/src/i18n/translations/en.yml +24 -21
  32. package/src/i18n/translations/es.yml +1 -0
  33. package/src/i18n/translations/fi.yml +1 -0
  34. package/src/i18n/translations/fr.yml +1 -0
  35. package/src/i18n/translations/hi.yml +1 -0
  36. package/src/i18n/translations/kk.yml +3 -0
  37. package/src/i18n/translations/pt.yml +1 -0
  38. package/src/i18n/translations/ru.yml +1 -0
  39. package/src/i18n/translations/uk.yml +1 -0
  40. package/src/i18n/translations/ur.yml +1 -0
  41. package/src/i18n/translations/zh.yml +1 -0
  42. package/src/i18n/translations.ts +5 -2
  43. package/src/layouts/Page.astro +3 -4
  44. package/src/layouts/components/Footer.astro +63 -10
  45. package/src/layouts/components/LanguagePicker.astro +2 -2
  46. package/src/layouts/components/MenuItem.astro +4 -4
  47. package/src/layouts/components/PageNavigation.astro +21 -29
  48. package/src/layouts/components/PageTitle.astro +4 -13
  49. package/src/pages/details-page/DefaultDetailsPage.astro +2 -15
  50. package/src/pages/details-page/components/AudioPanel.astro +5 -4
  51. package/src/pages/details-page/components/AudioPlayer.astro +4 -4
  52. package/src/pages/details-page/components/ContentSection.astro +42 -43
  53. package/src/pages/details-page/components/MediaCollection.astro +2 -6
  54. package/src/pages/details-page/components/main-details/OpenButton.astro +25 -19
  55. package/src/pages/details-page/components/main-details/ShareButton.astro +1 -1
  56. package/src/pages/details-page/components/more-details/Categories.astro +3 -5
  57. package/src/pages/details-page/components/more-details/Languages.astro +7 -3
  58. package/src/pages/details-page/utils/create-content-metadata.ts +40 -56
  59. package/src/pages/search-page/api/search.ts +1 -1
  60. package/src/pages/search-page/components/SearchFilter.astro +5 -5
  61. package/src/pages/search-page/components/SearchList.astro +22 -19
  62. package/src/utils/is-external-url.ts +34 -0
  63. package/src/utils/link-attributes.ts +10 -0
  64. package/src/utils/paths.ts +6 -0
  65. package/src/utils/urls.ts +12 -24
  66. 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 { TranslateMapFn } from "./translate-map"
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
- tMap: TranslateMapFn,
28
+ tConfigField: TranslateConfigFieldFn,
29
29
  ) => {
30
30
  const language = resolveLanguage(bcp47)
31
31
  return {
32
32
  ...language,
33
- labelText: tMap(language.label, {
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
- context: TranslationMapContext,
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): TranslateMapFn {
49
- return (translationMap: TranslationMap, context: TranslationMapContext) => {
50
- const currentLocaleValue = translationMap[currentLocale]
51
- if (currentLocaleValue) {
52
- return currentLocaleValue
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 defaultLocaleValue = translationMap[config.defaultLocale]
56
- if (defaultLocaleValue) {
57
- return defaultLocaleValue
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 "${context.path.join(".")}" in locales "${currentLocale}" and "${config.defaultLocale}"`,
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
  }
@@ -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
- Missing keys:
8
-
9
- - ln.details.edit
7
+ All keys have been translated. ✅
10
8
 
11
9
  ## **BN** ([bn.yml](./bn.yml))
12
10
 
13
- Missing keys:
14
-
15
- - ln.details.edit
11
+ All keys have been translated. ✅
16
12
 
17
13
  ## **DE** ([de.yml](./de.yml))
18
14
 
19
- Missing keys:
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
- Missing keys:
30
-
31
- - ln.details.edit
23
+ All keys have been translated. ✅
32
24
 
33
25
  ## **FI** ([fi.yml](./fi.yml))
34
26
 
35
- Missing keys:
36
-
37
- - ln.details.edit
27
+ All keys have been translated. ✅
38
28
 
39
29
  ## **FR** ([fr.yml](./fr.yml))
40
30
 
41
- Missing keys:
42
-
43
- - ln.details.edit
31
+ All keys have been translated. ✅
44
32
 
45
33
  ## **HI** ([hi.yml](./hi.yml))
46
34
 
47
- Missing keys:
48
-
49
- - ln.details.edit
35
+ All keys have been translated. ✅
50
36
 
51
37
  ## **KK** ([kk.yml](./kk.yml))
52
38
 
53
- Missing keys:
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
- Missing keys:
62
-
63
- - ln.details.edit
43
+ All keys have been translated. ✅
64
44
 
65
45
  ## **RU** ([ru.yml](./ru.yml))
66
46
 
67
- Missing keys:
68
-
69
- - ln.details.edit
47
+ All keys have been translated. ✅
70
48
 
71
49
  ## **UK** ([uk.yml](./uk.yml))
72
50
 
73
- Missing keys:
74
-
75
- - ln.details.edit
51
+ All keys have been translated. ✅
76
52
 
77
53
  ## **UR** ([ur.yml](./ur.yml))
78
54
 
79
- Missing keys:
80
-
81
- - ln.details.edit
55
+ All keys have been translated. ✅
82
56
 
83
57
  ## **ZH** ([zh.yml](./zh.yml))
84
58
 
85
- Missing keys:
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://sk8-ministries.pages.dev/en (not visible)
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://sk8-ministries.pages.dev/en (not visible)
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://sk8-ministries.pages.dev/en (first item in the main menu)
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://sk8-ministries.pages.dev/en/media
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://sk8-ministries.pages.dev/en/media/how-to-360-flip--en/
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://sk8-ministries.pages.dev/en/media
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://sk8-ministries.pages.dev/en/media/how-to-kickflip--en/
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://sk8-ministries.pages.dev/en/media
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://sk8-ministries.pages.dev/en/media/ollie-with-integrity--en/
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://sk8-ministries.pages.dev/en/media/ (not visible)
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://sk8-ministries.pages.dev/en/media/
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://sk8-ministries.pages.dev/en/media/
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://sk8-ministries.pages.dev/en/media/
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://sk8-ministries.pages.dev/en/media/
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://sk8-ministries.pages.dev/en/media/?language=de&type=book
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://sk8-ministries.pages.dev/en/media/ollie-with-integrity--en/
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://sk8-ministries.pages.dev/en/media/ollie-with-integrity--en/
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://sk8-ministries.pages.dev/en/media/ride-the-ramp-of-faith--en/
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://sk8-ministries.pages.dev/en/media/ride-the-ramp-of-faith--en/ (Firefox)
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://sk8-ministries.pages.dev/unexisting-path
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://sk8-ministries.pages.dev/unexisting-path
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: لنک کاپی ہو گیا