@riebeckite/plugin-l10n 0.0.14 → 0.0.16

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 CHANGED
@@ -92,4 +92,5 @@ Each translated entry receives one `<link rel="alternate" hreflang="…">` per e
92
92
 
93
93
  ## See also
94
94
 
95
- - [Plugin guide](../../../docs/en/reference/plugin-api.md)
95
+ - [Plugin guide](../../../docs/en/docs/reference/plugin-api.md)
96
+
package/README_ja.md CHANGED
@@ -71,6 +71,6 @@ l10n({
71
71
 
72
72
  独自検出の言語は frontmatter より弱く、ファイル名・ディレクトリより強く扱われます。`translationId` は明示的な翻訳グループ ID です。
73
73
 
74
- ## ????
74
+ ## 関連リンク
75
75
 
76
- - [?????????](../../../docs/ja/reference/plugin-api.md)
76
+ - [プラグイン API](../../../docs/ja/docs/reference/plugin-api.md)
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { getLocalization, getLocalizedContent, type L10nContent, type L10nDetectorContext, type L10nDetectorResult, type L10nOptions, type L10nUiOptions, type LanguageSwitcherRenderContext, type LocalizedContent, l10n, l10nPlugin, renderLanguageSwitcher, } from "./src/l10n.js";
1
+ export { getLanguageFromPath, getLocalization, getLocalizedContent, type L10nContent, type L10nDetectorContext, type L10nDetectorResult, type L10nOptions, type L10nUiOptions, type LanguageSwitcherRenderContext, type LocalizedContent, l10n, l10nPlugin, renderLanguageSwitcher, } from "./src/l10n.js";
package/dist/index.js CHANGED
@@ -31,6 +31,8 @@ function l10n(options) {
31
31
  let state = emptyState();
32
32
  return definePlugin({
33
33
  name: "l10n",
34
+ provides: ["content.localization"],
35
+ outputDependencies: [{ type: "global" }],
34
36
  options,
35
37
  assets: [createStyleAsset("l10n")],
36
38
  validateOptions: () => validateOptions(options).map((message) => ({ path: "l10n", message })),
@@ -110,7 +112,7 @@ function getLocalization(manifest, slug) {
110
112
  const lang = entry.publicLocation.metadata?.[LANGUAGE_METADATA_KEY];
111
113
  const translationId = entry.publicLocation.metadata?.[TRANSLATION_METADATA_KEY];
112
114
  if (!lang || !translationId) return null;
113
- const candidates = manifest.entries.filter(
115
+ const candidates = manifest.discoverableEntries.filter(
114
116
  (candidate) => candidate.publicLocation.metadata?.[TRANSLATION_METADATA_KEY] === translationId
115
117
  );
116
118
  const translations = Object.fromEntries(
@@ -131,11 +133,18 @@ function getLocalization(manifest, slug) {
131
133
  function getLocalizedContent(manifest, slug, lang) {
132
134
  const localization = getLocalization(manifest, slug);
133
135
  if (!localization) return null;
134
- const candidates = manifest.entries.filter(
136
+ const candidates = manifest.publicEntries.filter(
135
137
  (entry) => entry.publicLocation.metadata?.[TRANSLATION_METADATA_KEY] === localization.translationId && entry.publicLocation.metadata?.[LANGUAGE_METADATA_KEY] === lang
136
138
  );
137
139
  return candidates.length === 1 ? candidates[0] ?? null : null;
138
140
  }
141
+ function getLanguageFromPath(manifest, pathname) {
142
+ const firstSegment = pathname.split("/").filter(Boolean)[0];
143
+ if (!firstSegment) return void 0;
144
+ return manifest.discoverableEntries.map((entry) => entry.publicLocation.metadata?.[LANGUAGE_METADATA_KEY]).find(
145
+ (language) => language?.toLocaleLowerCase() === firstSegment.toLocaleLowerCase()
146
+ );
147
+ }
139
148
  function resolveOptions(options) {
140
149
  const validation = validateOptions(options);
141
150
  if (validation.length > 0) throw new Error(validation.join("\n"));
@@ -334,14 +343,14 @@ function readTranslationId(value) {
334
343
  return value.trim();
335
344
  }
336
345
  function withLocalization(location, content, options) {
337
- const unlocalizedPermalink = removeLocalePathSegments(
338
- location.permalink,
339
- content
340
- );
341
- const permalink = content.lang === options.defaultLang ? unlocalizedPermalink : prefixLanguage(unlocalizedPermalink, content.lang);
346
+ const permalink = localizePath(location.permalink, content, options);
342
347
  return {
343
348
  ...location,
344
349
  permalink,
350
+ redirects: location.redirects?.map((redirect) => ({
351
+ ...redirect,
352
+ path: localizePath(redirect.path, content, options)
353
+ })),
345
354
  metadata: {
346
355
  ...location.metadata,
347
356
  [LANGUAGE_METADATA_KEY]: content.lang,
@@ -349,6 +358,10 @@ function withLocalization(location, content, options) {
349
358
  }
350
359
  };
351
360
  }
361
+ function localizePath(pathname, content, options) {
362
+ const unlocalizedPath = removeLocalePathSegments(pathname, content);
363
+ return content.lang === options.defaultLang ? unlocalizedPath : prefixLanguage(unlocalizedPath, content.lang);
364
+ }
352
365
  function removeLocalePathSegments(permalink, content) {
353
366
  let result = permalink;
354
367
  const filenameLanguage = content.signals.filename;
@@ -385,36 +398,46 @@ function resolveLocalizedTarget(state, source, targetSlug) {
385
398
  return findTranslation(state, target.translationId, source.lang) ?? target;
386
399
  }
387
400
  function addLocalizationHeadTags(manifest, state) {
388
- for (const entry of manifest.entries) {
401
+ for (const entry of manifest.discoverableEntries) {
389
402
  const content = state.contents.get(entry.slug);
390
403
  if (!content) continue;
391
404
  const translations = uniqueLanguageEntries(
392
- manifest.entries.filter(
405
+ manifest.discoverableEntries.filter(
393
406
  (candidate) => candidate.publicLocation.metadata?.[TRANSLATION_METADATA_KEY] === content.translationId
394
407
  )
395
408
  );
396
- entry.headTags = [
397
- ...entry.headTags ?? [],
398
- ...translations.map((translation) => ({
409
+ const headTags = translations.map(
410
+ (translation) => ({
399
411
  tag: "link",
400
412
  attrs: {
401
413
  rel: "alternate",
402
414
  hreflang: translation.publicLocation.metadata?.[LANGUAGE_METADATA_KEY] ?? "",
403
415
  href: translation.permalink
404
416
  }
405
- }))
417
+ })
418
+ );
419
+ entry.headTags = [
420
+ ...(entry.headTags ?? []).filter(
421
+ (tag) => !headTags.some((generated) => sameHeadTag(tag, generated))
422
+ ),
423
+ ...headTags
406
424
  ];
407
425
  }
408
426
  }
409
427
  function addLanguageSwitchers(manifest, ui) {
410
428
  if (ui === false) return;
411
- for (const entry of manifest.entries) {
429
+ for (const entry of manifest.discoverableEntries) {
412
430
  const localization = getLocalization(manifest, entry.slug);
413
431
  if (!localization) continue;
414
432
  const html = ui.render({ localization });
415
- if (html) appendContentBodySlot(entry, ui.slot, html);
433
+ if (html && !entry.bodySlots?.[ui.slot]?.includes(html)) {
434
+ appendContentBodySlot(entry, ui.slot, html);
435
+ }
416
436
  }
417
437
  }
438
+ function sameHeadTag(left, right) {
439
+ return left.tag === right.tag && left.attrs?.rel === right.attrs?.rel && left.attrs?.hreflang === right.attrs?.hreflang && left.attrs?.href === right.attrs?.href;
440
+ }
418
441
  function uniqueLanguageEntries(entries) {
419
442
  return entries.filter((entry) => {
420
443
  const lang = entry.publicLocation.metadata?.[LANGUAGE_METADATA_KEY];
@@ -487,6 +510,7 @@ function emptyState() {
487
510
  };
488
511
  }
489
512
  export {
513
+ getLanguageFromPath,
490
514
  getLocalization,
491
515
  getLocalizedContent,
492
516
  l10n,
@@ -47,4 +47,5 @@ export declare const l10nPlugin: typeof l10n;
47
47
  export declare function getLocalization(manifest: ContentManifest, slug: string): LocalizedContent | null;
48
48
  /** Resolves an existing translation; missing translations return `null`. */
49
49
  export declare function getLocalizedContent(manifest: ContentManifest, slug: string, lang: string): ContentManifestEntry | null;
50
+ export declare function getLanguageFromPath(manifest: ContentManifest, pathname: string): string | undefined;
50
51
  export { renderLanguageSwitcher } from "./language-switcher.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riebeckite/plugin-l10n",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,11 +16,11 @@
16
16
  },
17
17
  "dependencies": {
18
18
  "yaml": "^2.9.0",
19
- "@riebeckite/core": "0.0.14"
19
+ "@riebeckite/core": "0.0.16"
20
20
  },
21
21
  "devDependencies": {
22
22
  "tsx": "^4.22.4",
23
- "@riebeckite/plugin-obsidian-markdown": "0.0.14"
23
+ "@riebeckite/plugin-obsidian-markdown": "0.0.16"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"