@riebeckite/plugin-l10n 0.0.17 → 0.0.19

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
@@ -17,16 +17,9 @@ export default defineConfig({
17
17
 
18
18
  ## Locale detection
19
19
 
20
- Use `README_ja.md`-style filenames with an underscore as the recommended form, matching this repository's convention. The plugin also accepts `README.en.md`, `README-en.md`, and configured BCP 47-style tags such as `README.en-US.md` and `README.zh-CN.md`.
20
+ Use `README.ja.md`-style filenames with a dot as the recommended form, matching this repository's convention. The plugin also accepts `README-ja.md`, `README_ja.md`, and configured BCP 47-style tags such as `README.en-US.md` and `README.zh-CN.md`.
21
21
 
22
- Directory detection is also supported:
23
-
24
- ```text
25
- content/en/README.md
26
- content/ja/README.md
27
- ```
28
-
29
- Only directories matching configured `languages` are treated as locales. Frontmatter works anywhere:
22
+ Directory detection is not supported. Only filename suffixes and frontmatter are used to infer a language. Frontmatter works anywhere:
30
23
 
31
24
  ```md
32
25
  ---
@@ -35,7 +28,7 @@ translation: getting-started
35
28
  ---
36
29
  ```
37
30
 
38
- Conventions may be mixed. Built-in precedence is **frontmatter > filename > directory > default language**. Conflicts emit `L10N_LANGUAGE_CONFLICT`; use `strict: true` to fail the build instead. A duplicate `translation + lang` emits `L10N_DUPLICATE_TRANSLATION` (and also fails in strict mode).
31
+ Conventions may be mixed. Built-in precedence is **frontmatter > custom detector > filename > default language**. Conflicts emit `L10N_LANGUAGE_CONFLICT`; use `strict: true` to fail the build instead. A duplicate `translation + lang` emits `L10N_DUPLICATE_TRANSLATION` (and also fails in strict mode).
39
32
 
40
33
  `translation` is independent of locale and filename. Use it to group files with unrelated paths or names:
41
34
 
@@ -73,7 +66,7 @@ Themes can override the default component through its `.l10n-switcher` CSS class
73
66
 
74
67
  ## Custom detector
75
68
 
76
- For another convention, provide `detect`. Its language is considered after frontmatter and before filename/directory; its `translationId` is explicit.
69
+ For another convention, provide `detect`. Its language is considered after frontmatter and before filename; its `translationId` is explicit.
77
70
 
78
71
  ```ts
79
72
  l10n({
@@ -92,5 +85,5 @@ Each translated entry receives one `<link rel="alternate" hreflang="…">` per e
92
85
 
93
86
  ## See also
94
87
 
95
- - [Plugin guide](../../../docs/en/docs/reference/plugin-api.md)
88
+ - [Plugin guide](../../../docs/docs/reference/plugin-api.en.md)
96
89
 
package/README_ja.md CHANGED
@@ -14,7 +14,7 @@ l10n({ defaultLang: "ja", languages: ["ja", "en", "zh-CN"] });
14
14
 
15
15
  ## ロケール検出と翻訳グループ
16
16
 
17
- ファイル名はこのリポジトリの慣例に合わせ、アンダースコアの `README_ja.md` 形式を推奨します。`README.ja.md`、`README-ja.md`、`README.en.md`、`README.en-US.md`、`README.zh-CN.md` も利用できます。設定済みの言語名に一致する先頭ディレクトリ(`en/README.md`)も検出します。
17
+ ファイル名はこのリポジトリの慣例に合わせ、ドットの `README.ja.md` 形式を推奨します。`README-ja.md`、`README_ja.md`、`README.en-US.md`、`README.zh-CN.md` も利用できます。ディレクトリ名による検出は行いません。
18
18
 
19
19
  frontmatter も利用できます。
20
20
 
@@ -25,7 +25,7 @@ translation: getting-started
25
25
  ---
26
26
  ```
27
27
 
28
- 組み合わせた場合の組み込み規則の優先順位は **frontmatter > ファイル名 > ディレクトリ > 既定言語** です。矛盾は `L10N_LANGUAGE_CONFLICT`、同一 `translation + lang` の重複は `L10N_DUPLICATE_TRANSLATION` として診断します。`strict: true` ではビルドを失敗させます。
28
+ 組み合わせた場合の組み込み規則の優先順位は **frontmatter > 独自検出 > ファイル名 > 既定言語** です。矛盾は `L10N_LANGUAGE_CONFLICT`、同一 `translation + lang` の重複は `L10N_DUPLICATE_TRANSLATION` として診断します。`strict: true` ではビルドを失敗させます。
29
29
 
30
30
  `translation` はロケール検出とは別です。異なるパス・ファイル名でも明示的な ID でグループ化できます。翻訳がない言語のページを複製・生成することはありません。
31
31
 
@@ -69,8 +69,8 @@ l10n({
69
69
  });
70
70
  ```
71
71
 
72
- 独自検出の言語は frontmatter より弱く、ファイル名・ディレクトリより強く扱われます。`translationId` は明示的な翻訳グループ ID です。
72
+ 独自検出の言語は frontmatter より弱く、ファイル名より強く扱われます。`translationId` は明示的な翻訳グループ ID です。
73
73
 
74
74
  ## 関連リンク
75
75
 
76
- - [プラグイン API](../../../docs/ja/docs/reference/plugin-api.md)
76
+ - [プラグイン API](../../../docs/docs/reference/plugin-api.md)
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  // src/l10n.ts
2
2
  import {
3
3
  appendContentBodySlot,
4
+ attachErrorPath,
4
5
  createStyleAsset,
5
6
  definePlugin
6
7
  } from "@riebeckite/core";
@@ -232,16 +233,11 @@ function detectContents(entries, options) {
232
233
  entry.path,
233
234
  options.languageByLowercase
234
235
  );
235
- const directoryLanguage = detectDirectoryLanguage(
236
- entry.path,
237
- options.languageByLowercase
238
- );
239
236
  const detectorContext = {
240
237
  path: entry.path,
241
238
  slug: entry.slug,
242
239
  frontmatter,
243
- filenameLanguage,
244
- directoryLanguage
240
+ filenameLanguage
245
241
  };
246
242
  const custom = options.detect?.(detectorContext);
247
243
  const frontmatterLanguage = configuredLanguage(
@@ -251,8 +247,7 @@ function detectContents(entries, options) {
251
247
  const signals = compactSignals({
252
248
  custom: configuredLanguage(custom?.lang, options.languageByLowercase),
253
249
  frontmatter: frontmatterLanguage,
254
- filename: filenameLanguage,
255
- directory: directoryLanguage
250
+ filename: filenameLanguage
256
251
  });
257
252
  addUnknownLanguageDiagnostic(
258
253
  diagnostics,
@@ -271,8 +266,8 @@ function detectContents(entries, options) {
271
266
  if (new Set(Object.values(signals)).size > 1) {
272
267
  diagnostics.push(conflictDiagnostic(entry, signals, options.strict));
273
268
  }
274
- const lang = signals.frontmatter ?? signals.custom ?? signals.filename ?? signals.directory ?? options.defaultLang;
275
- const translationId = readTranslationId(custom?.translationId ?? frontmatter.translation) ?? deriveTranslationId(entry.path, filenameLanguage, directoryLanguage);
269
+ const lang = signals.frontmatter ?? signals.custom ?? signals.filename ?? options.defaultLang;
270
+ const translationId = readTranslationId(custom?.translationId ?? frontmatter.translation) ?? deriveTranslationId(entry.path, filenameLanguage);
276
271
  const content = {
277
272
  path: entry.path,
278
273
  slug: entry.slug,
@@ -298,7 +293,12 @@ function parseFrontmatter(entry) {
298
293
  /^(?:\uFEFF)?---\s*\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n|$)/
299
294
  );
300
295
  if (!match) return {};
301
- const value = parse(match[1] ?? "");
296
+ let value;
297
+ try {
298
+ value = parse(match[1] ?? "");
299
+ } catch (error) {
300
+ throw attachErrorPath(error, entry.path);
301
+ }
302
302
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
303
303
  throw new Error(`Invalid frontmatter object: ${entry.path}`);
304
304
  }
@@ -312,10 +312,6 @@ function detectFilenameLanguage(path, languages) {
312
312
  }
313
313
  return void 0;
314
314
  }
315
- function detectDirectoryLanguage(path, languages) {
316
- const first = path.split("/")[0]?.toLowerCase();
317
- return first ? languages.get(first) : void 0;
318
- }
319
315
  function configuredLanguage(value, languages) {
320
316
  if (typeof value !== "string" || !value.trim()) return void 0;
321
317
  try {
@@ -324,9 +320,8 @@ function configuredLanguage(value, languages) {
324
320
  return void 0;
325
321
  }
326
322
  }
327
- function deriveTranslationId(path, filenameLanguage, directoryLanguage) {
323
+ function deriveTranslationId(path, filenameLanguage) {
328
324
  const parts = path.replace(/\.md$/i, "").split("/");
329
- if (directoryLanguage) parts.shift();
330
325
  const last = parts.pop() ?? "";
331
326
  const language = filenameLanguage?.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
332
327
  parts.push(
@@ -368,13 +363,6 @@ function removeLocalePathSegments(permalink, content) {
368
363
  const suffix = new RegExp(`([._-])${escapeRegExp(filenameLanguage)}$`, "i");
369
364
  result = result.replace(suffix, "");
370
365
  }
371
- const directoryLanguage = content.signals.directory;
372
- if (directoryLanguage) {
373
- result = result.replace(
374
- new RegExp(`^/${escapeRegExp(directoryLanguage)}(?=/|$)`, "i"),
375
- ""
376
- );
377
- }
378
366
  return result || "/";
379
367
  }
380
368
  function prefixLanguage(permalink, language) {
@@ -458,10 +446,10 @@ function conflictDiagnostic(entry, signals, strict) {
458
446
  slug: entry.slug,
459
447
  message: `Conflicting localization metadata (${Object.entries(signals).map(([source, language]) => `${source}: ${language}`).join(
460
448
  ", "
461
- )}); resolved to ${signals.frontmatter ?? signals.custom ?? signals.filename ?? signals.directory}.`,
449
+ )}); resolved to ${signals.frontmatter ?? signals.custom ?? signals.filename}.`,
462
450
  meta: {
463
451
  detected: signals,
464
- resolved: signals.frontmatter ?? signals.custom ?? signals.filename ?? signals.directory
452
+ resolved: signals.frontmatter ?? signals.custom ?? signals.filename
465
453
  }
466
454
  };
467
455
  }
@@ -6,7 +6,6 @@ export type L10nContent = {
6
6
  };
7
7
  export type L10nDetectorContext = L10nContent & {
8
8
  readonly filenameLanguage: string | undefined;
9
- readonly directoryLanguage: string | undefined;
10
9
  };
11
10
  /** A detector may provide a language and/or an explicit translation identity. */
12
11
  export type L10nDetectorResult = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@riebeckite/plugin-l10n",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
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.17"
19
+ "@riebeckite/core": "0.0.19"
20
20
  },
21
21
  "devDependencies": {
22
22
  "tsx": "^4.22.4",
23
- "@riebeckite/plugin-obsidian-markdown": "0.0.17"
23
+ "@riebeckite/plugin-obsidian-markdown": "0.0.19"
24
24
  },
25
25
  "publishConfig": {
26
26
  "access": "public"