@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 +5 -12
- package/README_ja.md +4 -4
- package/dist/index.js +14 -26
- package/dist/src/l10n.d.ts +0 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -17,16 +17,9 @@ export default defineConfig({
|
|
|
17
17
|
|
|
18
18
|
## Locale detection
|
|
19
19
|
|
|
20
|
-
Use `
|
|
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
|
|
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 >
|
|
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
|
|
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/
|
|
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
|
-
|
|
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 >
|
|
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
|
|
72
|
+
独自検出の言語は frontmatter より弱く、ファイル名より強く扱われます。`translationId` は明示的な翻訳グループ ID です。
|
|
73
73
|
|
|
74
74
|
## 関連リンク
|
|
75
75
|
|
|
76
|
-
- [プラグイン API](../../../docs/
|
|
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 ??
|
|
275
|
-
const translationId = readTranslationId(custom?.translationId ?? frontmatter.translation) ?? deriveTranslationId(entry.path, filenameLanguage
|
|
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
|
-
|
|
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
|
|
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
|
|
449
|
+
)}); resolved to ${signals.frontmatter ?? signals.custom ?? signals.filename}.`,
|
|
462
450
|
meta: {
|
|
463
451
|
detected: signals,
|
|
464
|
-
resolved: signals.frontmatter ?? signals.custom ?? signals.filename
|
|
452
|
+
resolved: signals.frontmatter ?? signals.custom ?? signals.filename
|
|
465
453
|
}
|
|
466
454
|
};
|
|
467
455
|
}
|
package/dist/src/l10n.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
19
|
+
"@riebeckite/core": "0.0.19"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
22
|
"tsx": "^4.22.4",
|
|
23
|
-
"@riebeckite/plugin-obsidian-markdown": "0.0.
|
|
23
|
+
"@riebeckite/plugin-obsidian-markdown": "0.0.19"
|
|
24
24
|
},
|
|
25
25
|
"publishConfig": {
|
|
26
26
|
"access": "public"
|