@markuplint/i18n 5.0.0-rc.2 → 5.0.0-rc.5

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/$schema.json CHANGED
@@ -186,13 +186,14 @@
186
186
  "additionalProperties": false,
187
187
  "properties": {
188
188
  "{0} {1}": { "type": "string" },
189
+ "{0} {1} has no cells beginning in it": { "type": "string" },
190
+ "{0} {1} have no cells beginning in them": { "type": "string" },
189
191
  "{0:c} and {1:c}": { "type": "string" },
190
192
  "{0:c} on {1}": { "type": "string" },
191
193
  "{0} ({1})": { "type": "string" },
192
194
  "{0} according to {1}": { "type": "string" },
193
195
  "{0} are causing {1}": { "type": "string" },
194
196
  "{0} as {1}": { "type": "string" },
195
- "{0} associates only {1}": { "type": "string" },
196
197
  "{0} behaves the same as {1} if {2}": { "type": "string" },
197
198
  "{0} chars": { "type": "string" },
198
199
  "{0} contradicts {1}": { "type": "string" },
package/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [5.0.0-rc.5](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.4...v5.0.0-rc.5) (2026-08-28)
7
+
8
+ ### Code Refactoring
9
+
10
+ - **rules:** redesign v5 rule system — naming, splits, specConformance ([#3989](https://github.com/markuplint/markuplint/issues/3989)) ([e925565](https://github.com/markuplint/markuplint/commit/e925565ce537848d7d1573369723cbce724a841b)), closes [#4](https://github.com/markuplint/markuplint/issues/4) [#aside-conditional-role-mapping-aria-13](https://github.com/markuplint/markuplint/issues/aside-conditional-role-mapping-aria-13)
11
+
12
+ ### Features
13
+
14
+ - **rules:** report HTML LS table model errors in table-row-column-alignment ([#3953](https://github.com/markuplint/markuplint/issues/3953)) ([bacdcd6](https://github.com/markuplint/markuplint/commit/bacdcd697f76300153388f5b1cabaa8504f08d1f)), closes [#3916](https://github.com/markuplint/markuplint/issues/3916) [#3915](https://github.com/markuplint/markuplint/issues/3915) [#3916](https://github.com/markuplint/markuplint/issues/3916) [#3915](https://github.com/markuplint/markuplint/issues/3915)
15
+
16
+ ### BREAKING CHANGES
17
+
18
+ - **rules:** with no alias coverage.
19
+
20
+ # [5.0.0-rc.4](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.3...v5.0.0-rc.4) (2026-04-19)
21
+
22
+ **Note:** Version bump only for package @markuplint/i18n
23
+
24
+ # [5.0.0-rc.3](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.2...v5.0.0-rc.3) (2026-04-19)
25
+
26
+ **Note:** Version bump only for package @markuplint/i18n
27
+
6
28
  # [5.0.0-rc.2](https://github.com/markuplint/markuplint/compare/v5.0.0-rc.1...v5.0.0-rc.2) (2026-04-15)
7
29
 
8
30
  ### Features
package/CLAUDE.md ADDED
@@ -0,0 +1,13 @@
1
+ # @markuplint/i18n
2
+
3
+ Constraints not derivable from code:
4
+
5
+ - `$schema.json` is maintained **by hand** and uses `additionalProperties: false`.
6
+ Every keyword or sentence added to a locale file MUST also be added to
7
+ `$schema.json`, or the locale fails schema validation. Keep the files in sync.
8
+ - `en.json` is intentionally minimal: the English sentence key itself serves as
9
+ the template, so `en.json` only carries entries that need capitalization or
10
+ special formatting. Do NOT mirror every `ja.json` entry into `en.json`.
11
+
12
+ Placeholder syntax (`{0}`, `{0:c}` complement, `{0*}` no-translate) is documented
13
+ in `src/translator.ts` JSDoc.
package/cjs/index.d.ts CHANGED
@@ -1,2 +1,24 @@
1
+ /**
2
+ * @module @markuplint/i18n
3
+ *
4
+ * Internationalization for markuplint rule messages.
5
+ *
6
+ * Locale dictionary contract (`locales/*.json` and `$schema.json`):
7
+ * - Sentence template keys are the English sentences themselves, and an untranslated
8
+ * keyword falls back to its own key. Therefore `locales/en.json` needs no `sentences`
9
+ * section and holds only keyword overrides where the lowercase key cannot serve as
10
+ * display text (e.g. `"html elements"` → `"HTML elements"`), since keyword lookup
11
+ * keys are lowercase.
12
+ * - `locales/ja.json` is the reference dictionary: it is expected to translate every
13
+ * keyword and sentence template, and serves as the template for new languages.
14
+ * - `$schema.json` is the source of truth for valid keys. It intentionally declares
15
+ * `additionalProperties: false` so that a keyword or sentence added to a locale file
16
+ * without a matching schema entry fails validation instead of silently never matching.
17
+ * The schema is shared by all locales, so adding a language requires no schema change.
18
+ * - Translated sentence templates may reorder placeholders freely (e.g. `"{0} is not
19
+ * allowed in {1}"` → `"{1}に{0}は許可されていません"`) because placeholder numbers
20
+ * refer to translator argument positions, not to their position in the English
21
+ * template.
22
+ */
1
23
  export { translator } from './translator.js';
2
24
  export type { Translator, LocaleSet } from './types.js';
package/cjs/index.js CHANGED
@@ -1,4 +1,26 @@
1
1
  "use strict";
2
+ /**
3
+ * @module @markuplint/i18n
4
+ *
5
+ * Internationalization for markuplint rule messages.
6
+ *
7
+ * Locale dictionary contract (`locales/*.json` and `$schema.json`):
8
+ * - Sentence template keys are the English sentences themselves, and an untranslated
9
+ * keyword falls back to its own key. Therefore `locales/en.json` needs no `sentences`
10
+ * section and holds only keyword overrides where the lowercase key cannot serve as
11
+ * display text (e.g. `"html elements"` → `"HTML elements"`), since keyword lookup
12
+ * keys are lowercase.
13
+ * - `locales/ja.json` is the reference dictionary: it is expected to translate every
14
+ * keyword and sentence template, and serves as the template for new languages.
15
+ * - `$schema.json` is the source of truth for valid keys. It intentionally declares
16
+ * `additionalProperties: false` so that a keyword or sentence added to a locale file
17
+ * without a matching schema entry fails validation instead of silently never matching.
18
+ * The schema is shared by all locales, so adding a language requires no schema change.
19
+ * - Translated sentence templates may reorder placeholders freely (e.g. `"{0} is not
20
+ * allowed in {1}"` → `"{1}に{0}は許可されていません"`) because placeholder numbers
21
+ * refer to translator argument positions, not to their position in the English
22
+ * template.
23
+ */
2
24
  Object.defineProperty(exports, "__esModule", { value: true });
3
25
  exports.translator = void 0;
4
26
  var translator_js_1 = require("./translator.js");
@@ -8,21 +8,21 @@ import type { LocaleSet, Primitive, Translator } from './types.js';
8
8
  * - **List formatting**: `t(["apple", "banana", "cherry"], true)` – formats an array of strings
9
9
  * into a human-readable list (e.g. `"apple", "banana" and "cherry"`).
10
10
  *
11
+ * Placeholder flags carry translation intent:
12
+ * - `{0:c}` resolves through a `c:`-prefixed keyword (complement form); see `translateKeyword` below.
13
+ * - `{0*}` inserts the argument verbatim, for dynamic values such as attribute names or
14
+ * user input that must not go through keyword translation.
15
+ *
11
16
  * @param localeSet - The locale configuration providing translations and formatting rules
12
17
  * @returns A translator function for producing localized messages
13
18
  */
14
19
  export declare function translator(localeSet?: LocaleSet): Translator;
15
20
  /**
16
- * Creates a tagged template literal translator function.
17
- *
18
- * Allows using template literal syntax for translations:
19
21
  * ```ts
20
22
  * const tt = taggedTemplateTranslator(localeSet);
21
23
  * const msg = tt`The ${name} is ${value}`;
22
24
  * ```
23
25
  *
24
26
  * @experimental
25
- * @param localeSet - The locale configuration providing translations and formatting rules
26
- * @returns A tagged template function that produces localized strings
27
27
  */
28
28
  export declare function taggedTemplateTranslator(localeSet?: LocaleSet): (strings: Readonly<TemplateStringsArray>, ...keys: readonly Primitive[]) => string;
package/cjs/translator.js CHANGED
@@ -17,6 +17,11 @@ const defaultListFormat = {
17
17
  * - **List formatting**: `t(["apple", "banana", "cherry"], true)` – formats an array of strings
18
18
  * into a human-readable list (e.g. `"apple", "banana" and "cherry"`).
19
19
  *
20
+ * Placeholder flags carry translation intent:
21
+ * - `{0:c}` resolves through a `c:`-prefixed keyword (complement form); see `translateKeyword` below.
22
+ * - `{0*}` inserts the argument verbatim, for dynamic values such as attribute names or
23
+ * user input that must not go through keyword translation.
24
+ *
20
25
  * @param localeSet - The locale configuration providing translations and formatting rules
21
26
  * @returns A translator function for producing localized messages
22
27
  */
@@ -69,17 +74,12 @@ function translator(localeSet) {
69
74
  };
70
75
  }
71
76
  /**
72
- * Creates a tagged template literal translator function.
73
- *
74
- * Allows using template literal syntax for translations:
75
77
  * ```ts
76
78
  * const tt = taggedTemplateTranslator(localeSet);
77
79
  * const msg = tt`The ${name} is ${value}`;
78
80
  * ```
79
81
  *
80
82
  * @experimental
81
- * @param localeSet - The locale configuration providing translations and formatting rules
82
- * @returns A tagged template function that produces localized strings
83
83
  */
84
84
  function taggedTemplateTranslator(localeSet) {
85
85
  const t = translator(localeSet);
@@ -97,6 +97,16 @@ function taggedTemplateTranslator(localeSet) {
97
97
  return t(template, ...keys);
98
98
  };
99
99
  }
100
+ /**
101
+ * Resolves a keyword to its translation in the locale set.
102
+ *
103
+ * When the `c` flag is given (from a `{n:c}` placeholder), the lookup tries the
104
+ * `c:`-prefixed dictionary entry first. Complement (`c:`) keywords exist for languages
105
+ * such as Japanese where the translation must be a predicate that attaches to the
106
+ * preceding subject (e.g. `c:deprecated` → 「は非推奨です」, yielding 「〇〇は非推奨です」),
107
+ * which cannot be produced from the plain keyword translation. The plain keyword
108
+ * (without `c:`) may still exist as a separate dictionary entry for non-complement use.
109
+ */
100
110
  function translateKeyword(keyword, flag, localeSet) {
101
111
  // No translate
102
112
  if (/^%[^%]+%$/.test(keyword)) {
package/esm/index.d.ts CHANGED
@@ -1,2 +1,24 @@
1
+ /**
2
+ * @module @markuplint/i18n
3
+ *
4
+ * Internationalization for markuplint rule messages.
5
+ *
6
+ * Locale dictionary contract (`locales/*.json` and `$schema.json`):
7
+ * - Sentence template keys are the English sentences themselves, and an untranslated
8
+ * keyword falls back to its own key. Therefore `locales/en.json` needs no `sentences`
9
+ * section and holds only keyword overrides where the lowercase key cannot serve as
10
+ * display text (e.g. `"html elements"` → `"HTML elements"`), since keyword lookup
11
+ * keys are lowercase.
12
+ * - `locales/ja.json` is the reference dictionary: it is expected to translate every
13
+ * keyword and sentence template, and serves as the template for new languages.
14
+ * - `$schema.json` is the source of truth for valid keys. It intentionally declares
15
+ * `additionalProperties: false` so that a keyword or sentence added to a locale file
16
+ * without a matching schema entry fails validation instead of silently never matching.
17
+ * The schema is shared by all locales, so adding a language requires no schema change.
18
+ * - Translated sentence templates may reorder placeholders freely (e.g. `"{0} is not
19
+ * allowed in {1}"` → `"{1}に{0}は許可されていません"`) because placeholder numbers
20
+ * refer to translator argument positions, not to their position in the English
21
+ * template.
22
+ */
1
23
  export { translator } from './translator.js';
2
24
  export type { Translator, LocaleSet } from './types.js';
package/esm/index.mjs CHANGED
@@ -1 +1,23 @@
1
+ /**
2
+ * @module @markuplint/i18n
3
+ *
4
+ * Internationalization for markuplint rule messages.
5
+ *
6
+ * Locale dictionary contract (`locales/*.mjson` and `$schema.mjson`):
7
+ * - Sentence template keys are the English sentences themselves, and an untranslated
8
+ * keyword falls back to its own key. Therefore `locales/en.mjson` needs no `sentences`
9
+ * section and holds only keyword overrides where the lowercase key cannot serve as
10
+ * display text (e.g. `"html elements"` → `"HTML elements"`), since keyword lookup
11
+ * keys are lowercase.
12
+ * - `locales/ja.mjson` is the reference dictionary: it is expected to translate every
13
+ * keyword and sentence template, and serves as the template for new languages.
14
+ * - `$schema.mjson` is the source of truth for valid keys. It intentionally declares
15
+ * `additionalProperties: false` so that a keyword or sentence added to a locale file
16
+ * without a matching schema entry fails validation instead of silently never matching.
17
+ * The schema is shared by all locales, so adding a language requires no schema change.
18
+ * - Translated sentence templates may reorder placeholders freely (e.g. `"{0} is not
19
+ * allowed in {1}"` → `"{1}に{0}は許可されていません"`) because placeholder numbers
20
+ * refer to translator argument positions, not to their position in the English
21
+ * template.
22
+ */
1
23
  export { translator } from './translator.mjs';
@@ -8,21 +8,21 @@ import type { LocaleSet, Primitive, Translator } from './types.js';
8
8
  * - **List formatting**: `t(["apple", "banana", "cherry"], true)` – formats an array of strings
9
9
  * into a human-readable list (e.g. `"apple", "banana" and "cherry"`).
10
10
  *
11
+ * Placeholder flags carry translation intent:
12
+ * - `{0:c}` resolves through a `c:`-prefixed keyword (complement form); see `translateKeyword` below.
13
+ * - `{0*}` inserts the argument verbatim, for dynamic values such as attribute names or
14
+ * user input that must not go through keyword translation.
15
+ *
11
16
  * @param localeSet - The locale configuration providing translations and formatting rules
12
17
  * @returns A translator function for producing localized messages
13
18
  */
14
19
  export declare function translator(localeSet?: LocaleSet): Translator;
15
20
  /**
16
- * Creates a tagged template literal translator function.
17
- *
18
- * Allows using template literal syntax for translations:
19
21
  * ```ts
20
22
  * const tt = taggedTemplateTranslator(localeSet);
21
23
  * const msg = tt`The ${name} is ${value}`;
22
24
  * ```
23
25
  *
24
26
  * @experimental
25
- * @param localeSet - The locale configuration providing translations and formatting rules
26
- * @returns A tagged template function that produces localized strings
27
27
  */
28
28
  export declare function taggedTemplateTranslator(localeSet?: LocaleSet): (strings: Readonly<TemplateStringsArray>, ...keys: readonly Primitive[]) => string;
@@ -13,6 +13,11 @@ const defaultListFormat = {
13
13
  * - **List formatting**: `t(["apple", "banana", "cherry"], true)` – formats an array of strings
14
14
  * into a human-readable list (e.g. `"apple", "banana" and "cherry"`).
15
15
  *
16
+ * Placeholder flags carry translation intent:
17
+ * - `{0:c}` resolves through a `c:`-prefixed keyword (complement form); see `translateKeyword` below.
18
+ * - `{0*}` inserts the argument verbatim, for dynamic values such as attribute names or
19
+ * user input that must not go through keyword translation.
20
+ *
16
21
  * @param localeSet - The locale configuration providing translations and formatting rules
17
22
  * @returns A translator function for producing localized messages
18
23
  */
@@ -65,17 +70,12 @@ export function translator(localeSet) {
65
70
  };
66
71
  }
67
72
  /**
68
- * Creates a tagged template literal translator function.
69
- *
70
- * Allows using template literal syntax for translations:
71
73
  * ```ts
72
74
  * const tt = taggedTemplateTranslator(localeSet);
73
75
  * const msg = tt`The ${name} is ${value}`;
74
76
  * ```
75
77
  *
76
78
  * @experimental
77
- * @param localeSet - The locale configuration providing translations and formatting rules
78
- * @returns A tagged template function that produces localized strings
79
79
  */
80
80
  export function taggedTemplateTranslator(localeSet) {
81
81
  const t = translator(localeSet);
@@ -93,6 +93,16 @@ export function taggedTemplateTranslator(localeSet) {
93
93
  return t(template, ...keys);
94
94
  };
95
95
  }
96
+ /**
97
+ * Resolves a keyword to its translation in the locale set.
98
+ *
99
+ * When the `c` flag is given (from a `{n:c}` placeholder), the lookup tries the
100
+ * `c:`-prefixed dictionary entry first. Complement (`c:`) keywords exist for languages
101
+ * such as Japanese where the translation must be a predicate that attaches to the
102
+ * preceding subject (e.g. `c:deprecated` → 「は非推奨です」, yielding 「〇〇は非推奨です」),
103
+ * which cannot be produced from the plain keyword translation. The plain keyword
104
+ * (without `c:`) may still exist as a separate dictionary entry for non-complement use.
105
+ */
96
106
  function translateKeyword(keyword, flag, localeSet) {
97
107
  // No translate
98
108
  if (/^%[^%]+%$/.test(keyword)) {
package/locales/ja.json CHANGED
@@ -170,13 +170,14 @@
170
170
  },
171
171
  "sentences": {
172
172
  "{0} {1}": "{0}{1}",
173
+ "{0} {1} has no cells beginning in it": "{0}つの{1}に開始するセルがありません",
174
+ "{0} {1} have no cells beginning in them": "{0}つの{1}に開始するセルがありません",
173
175
  "{0:c} and {1:c}": "{0}且つ、{1}",
174
176
  "{0:c} on {1}": "{1}では、{0:c}",
175
177
  "{0} ({1})": "{0}({1})",
176
178
  "{0} according to {1}": "{1}において、{0}",
177
179
  "{0} are causing {1}": "{0}が{1}を引き起こしています",
178
180
  "{0} as {1}": "{1}として{0}",
179
- "{0} associates only {1}": "{0}は{1}だけを関連付けます",
180
181
  "{0} behaves the same as {1} if {2}": "{0}は{2}の場合、{1}と同じ振る舞いをします",
181
182
  "{0} chars": "{0}文字",
182
183
  "{0} contradicts {1}": "{0}は{1}と矛盾しています",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markuplint/i18n",
3
- "version": "5.0.0-rc.2",
3
+ "version": "5.0.0-rc.5",
4
4
  "description": "Internationalization for markuplint",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,7 +10,7 @@
10
10
  "author": "Yusuke Hirao <yusukehirao@me.com>",
11
11
  "license": "MIT",
12
12
  "engines": {
13
- "node": ">=22"
13
+ "node": ">=24"
14
14
  },
15
15
  "main": "./cjs/index.js",
16
16
  "types": "./cjs/index.d.ts",
@@ -45,5 +45,5 @@
45
45
  "clean:esm": "tsc --build --clean tsconfig.build.json",
46
46
  "clean:cjs": "tsc --build --clean tsconfig.build-cjs.json"
47
47
  },
48
- "gitHead": "e43763858d9234c417053becc73dbd088c1e7ea6"
48
+ "gitHead": "8d87463af2ff3f1b83fb28da20f1819362cf3555"
49
49
  }
package/SKILL.md DELETED
@@ -1,73 +0,0 @@
1
- ---
2
- description: Maintenance tasks for @markuplint/i18n — internationalization for markuplint
3
- globs:
4
- - packages/@markuplint/i18n/src/**/*.ts
5
- - packages/@markuplint/i18n/locales/*.json
6
- - packages/@markuplint/i18n/$schema.json
7
- alwaysApply: false
8
- ---
9
-
10
- # @markuplint/i18n Maintenance
11
-
12
- You are maintaining `@markuplint/i18n`, the internationalization package for markuplint.
13
-
14
- ## Architecture
15
-
16
- See [README.md](README.md) for the full API documentation including translator usage, placeholder syntax, and locale formatting.
17
-
18
- For detailed maintenance procedures, see [docs/maintenance.md](docs/maintenance.md) ([Japanese](docs/maintenance.ja.md)).
19
-
20
- ## Key Files
21
-
22
- | File | Role |
23
- | ------------------- | ---------------------------------------------------------------------------------------------- |
24
- | `locales/ja.json` | Japanese locale dictionary (keywords + sentences + listFormat) |
25
- | `locales/en.json` | English locale dictionary (minimal; only entries needing capitalization or special formatting) |
26
- | `$schema.json` | JSON Schema for locale files (`additionalProperties: false`) |
27
- | `src/translator.ts` | Core translation logic |
28
- | `src/types.ts` | `LocaleSet`, `ListFormat`, `Translator` types |
29
-
30
- ## Tasks
31
-
32
- ### add-keyword
33
-
34
- Add a new keyword used in rule messages.
35
-
36
- 1. Add to `locales/ja.json` under `keywords` (alphabetical order, lowercase key)
37
- - Normal keyword: `"tag name": "タグ名"`
38
- - Complement keyword (for `:c` flag): `"c:deprecated": "は非推奨です"`
39
- 2. Add to `locales/en.json` under `keywords` only if capitalization or special formatting is needed
40
- 3. Add to `$schema.json` under `keywords.properties` as `{ "type": "string" }`
41
- 4. Test: `yarn test --scope @markuplint/i18n`
42
- 5. Build: `yarn build --scope @markuplint/i18n`
43
-
44
- **Important**: `$schema.json` uses `additionalProperties: false`. A keyword not defined in the schema will cause validation errors. Always keep the three files in sync.
45
-
46
- ### add-sentence
47
-
48
- Add a new sentence template for rule messages.
49
-
50
- 1. Design the English template as the key
51
- - Placeholders: `{0}`, `{1}`, `{2}`...
52
- - Complement flag: `{0:c}` (resolves to `c:` prefixed keyword in Japanese)
53
- - No-translate mark: `{0*}` (skips translation for that placeholder)
54
- 2. Add to `locales/ja.json` under `sentences` (placeholder order may differ for natural Japanese)
55
- 3. Add to `$schema.json` under `sentences.properties` as `{ "type": "string" }`
56
- 4. `en.json` does not need a `sentences` entry (the English key itself serves as the template)
57
- 5. Test: `yarn test --scope @markuplint/i18n`
58
-
59
- ### add-language
60
-
61
- Add support for a new language.
62
-
63
- 1. Create `locales/<lang>.json` using `ja.json` as a template
64
- - `listFormat`: Define quote characters and separator for the language
65
- - `keywords`: Translate all keywords
66
- - `sentences`: Translate all sentence templates
67
- 2. Add an export entry in `package.json`:
68
- ```json
69
- "./locales/<lang>.json": { "import": "./locales/<lang>.json", "require": "./locales/<lang>.json" }
70
- ```
71
- 3. `$schema.json` is shared across all languages (no changes needed)
72
- 4. Add test cases in `src/index.spec.ts`
73
- 5. Test: `yarn test --scope @markuplint/i18n`
@@ -1,208 +0,0 @@
1
- # @markuplint/i18n メンテナンスガイド
2
-
3
- ## 概要
4
-
5
- `@markuplint/i18n` パッケージは、markuplint のルールメッセージの国際化を提供します。
6
-
7
- - **ロケール辞書** (`locales/*.json`) — 言語ごとのキーワード、文テンプレート、リスト書式ルール
8
- - **翻訳エンジン** (`src/translator.ts`) — テンプレートのキーワード置換、補語形式、リスト整形を処理
9
- - **JSON Schema** (`$schema.json`) — 厳密なプロパティチェックでロケールファイルを検証
10
-
11
- ### ファイル構成
12
-
13
- ```
14
- packages/@markuplint/i18n/
15
- ├── locales/
16
- │ ├── ja.json # 日本語辞書(完全版)
17
- │ └── en.json # 英語辞書(最小限のオーバーライド)
18
- ├── src/
19
- │ ├── translator.ts # 翻訳コアロジック
20
- │ ├── types.ts # LocaleSet, Translator 型定義
21
- │ └── index.spec.ts # テストスイート
22
- ├── $schema.json # ロケール JSON Schema
23
- └── package.json
24
- ```
25
-
26
- ## 3ファイル同期ルール
27
-
28
- キーワードや文テンプレートを追加する際、3つのファイルを同期する必要があります。
29
-
30
- | ファイル | 役割 | 必須? |
31
- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------- |
32
- | `$schema.json` | 許可されるプロパティキーを定義。`additionalProperties: false` のため、ここに定義されていないキーはバリデーションエラーになる。 | **常に必須** |
33
- | `locales/ja.json` | すべてのキーワードと文テンプレートの日本語翻訳。 | **常に必須** |
34
- | `locales/en.json` | 英語のオーバーライド。大文字化や特殊な書式が必要な場合のみ(例: `"html elements"` → `"HTML elements"`)。 | 必要な場合のみ |
35
-
36
- スキーマが有効なキーの定義元です。`ja.json` にキーワードを追加しても `$schema.json` に追加しなければ、ロケールファイルのスキーマ検証が失敗します。
37
-
38
- ## 単語を追加する
39
-
40
- キーワードは、ルールメッセージの構成要素として使われる単語または短いフレーズです。ロケールファイルの `keywords` セクションに定義します。
41
-
42
- ### 手順
43
-
44
- 1. **`ja.json`** の `keywords` にアルファベット順で追加:
45
-
46
- ```json
47
- {
48
- "keywords": {
49
- "focusable": "フォーカス可能"
50
- }
51
- }
52
- ```
53
-
54
- - キーは英語の小文字
55
- - 値は日本語の翻訳
56
-
57
- 2. **`en.json`** の `keywords` には必要な場合のみ追加:
58
-
59
- ```json
60
- {
61
- "keywords": {
62
- "html elements": "HTML elements"
63
- }
64
- }
65
- ```
66
-
67
- ほとんどの英語キーワードはエントリ不要です。キーがそのまま使用されます。
68
-
69
- 3. **`$schema.json`** の `keywords.properties` に追加:
70
-
71
- ```json
72
- {
73
- "keywords": {
74
- "properties": {
75
- "focusable": { "type": "string" }
76
- }
77
- }
78
- }
79
- ```
80
-
81
- 4. **テスト**: `yarn test --scope @markuplint/i18n`
82
- 5. **ビルド**: `yarn build --scope @markuplint/i18n`
83
-
84
- ### 補語キーワード
85
-
86
- 補語キーワードは `c:` プレフィックスを使い、プレースホルダーに `:c` フラグ(例: `{0:c}`)が付いた場合に解決されます。日本語では主語に続く述語として機能します。
87
-
88
- | ロケールのキー | テンプレートでの使用 | 出力例(ja) |
89
- | ---------------------------------------- | -------------------------------------------- | ------------------------------ |
90
- | `"c:deprecated": "は非推奨です"` | `"{0} is {1:c}"` + キーワード `"deprecated"` | `「要素」は非推奨です` |
91
- | `"c:disallowed": "は許可されていません"` | `"{0} is {1:c}"` + キーワード `"disallowed"` | `「属性」は許可されていません` |
92
- | `"c:prohibited": "は禁止されています"` | `"{0} is {1:c}"` + キーワード `"prohibited"` | `「属性」は禁止されています` |
93
-
94
- 補語キーワードを追加する際:
95
-
96
- 1. `ja.json` の keywords に `"c:<word>"` を追加
97
- 2. `$schema.json` の keywords properties に `"c:<word>"` を追加
98
- 3. 補語なしバージョン(`c:` なし)も別のキーワードとして必要な場合がある
99
-
100
- ## フレーズを追加する
101
-
102
- 文テンプレートは、プレースホルダー付きのメッセージパターンを定義します。ロケールファイルの `sentences` セクションに定義します。
103
-
104
- ### 手順
105
-
106
- 1. **英語テンプレート**をキーとして設計:
107
-
108
- ```
109
- "{0} conflicts with {1}"
110
- ```
111
-
112
- プレースホルダー構文:
113
- - `{0}`, `{1}`, `{2}` — 位置パラメータ、キーワードとして翻訳される
114
- - `{0:c}` — 補語フラグ、日本語では `c:` プレフィックスキーワードに解決
115
- - `{0*}` — 翻訳スキップ、値がキーワード検索なしでそのまま挿入される
116
-
117
- 2. **`ja.json`** の `sentences` に追加:
118
-
119
- ```json
120
- {
121
- "sentences": {
122
- "{0} conflicts with {1}": "{0}は{1}と競合しています"
123
- }
124
- }
125
- ```
126
-
127
- 日本語の自然な語順にするため、プレースホルダーの順序は英語と異なってもよい。
128
-
129
- 3. **`$schema.json`** の `sentences.properties` に追加:
130
-
131
- ```json
132
- {
133
- "sentences": {
134
- "properties": {
135
- "{0} conflicts with {1}": { "type": "string" }
136
- }
137
- }
138
- }
139
- ```
140
-
141
- 4. **`en.json` に sentences エントリは不要**。英語のキー自体がテンプレートとして使用されます。翻訳が見つからない場合、translator はキーをそのまま使います。
142
-
143
- 5. **テスト**: `yarn test --scope @markuplint/i18n`
144
-
145
- ### プレースホルダーの並べ替え
146
-
147
- 日本語と英語では語順が異なります。文テンプレートを翻訳する際、プレースホルダーは自由に並べ替えできます:
148
-
149
- - 英語: `"{0} is not allowed in {1}"`
150
- - 日本語: `"{1}に{0}は許可されていません"`
151
-
152
- プレースホルダーの番号は、translator に渡される引数の位置を指し、文字列内の位置ではありません。
153
-
154
- ## 新しい言語を追加する
155
-
156
- まったく新しい言語のサポートを追加する手順です。
157
-
158
- ### 手順
159
-
160
- 1. **`locales/<lang>.json`** を `ja.json` をテンプレートにして作成:
161
-
162
- ```json
163
- {
164
- "$schema": "../$schema.json",
165
- "listFormat": {
166
- "quoteStart": "\"",
167
- "quoteEnd": "\"",
168
- "separator": ", "
169
- },
170
- "keywords": {
171
- "attribute": "<翻訳>",
172
- "element": "<翻訳>"
173
- },
174
- "sentences": {
175
- "{0} is {1}": "<翻訳テンプレート>"
176
- }
177
- }
178
- ```
179
-
180
- - `listFormat`: 言語に適した引用符と区切り文字を定義
181
- - `keywords`: `ja.json` のすべてのキーワードを翻訳
182
- - `sentences`: `ja.json` のすべての文テンプレートを翻訳
183
-
184
- 2. **`package.json`** にエクスポートエントリを追加:
185
-
186
- ```json
187
- {
188
- "exports": {
189
- "./locales/<lang>.json": {
190
- "import": "./locales/<lang>.json",
191
- "require": "./locales/<lang>.json"
192
- }
193
- }
194
- }
195
- ```
196
-
197
- 3. **`$schema.json` の変更は不要** — スキーマは全言語で共有されます。
198
-
199
- 4. **`src/index.spec.ts`** に新しいロケールのテストケースを追加。
200
-
201
- 5. **テスト**: `yarn test --scope @markuplint/i18n`
202
-
203
- ## コマンドリファレンス
204
-
205
- | コマンド | 説明 |
206
- | ------------------------------------- | ------------------ |
207
- | `yarn test --scope @markuplint/i18n` | テスト実行 |
208
- | `yarn build --scope @markuplint/i18n` | パッケージのビルド |
@@ -1,208 +0,0 @@
1
- # @markuplint/i18n Maintenance Guide
2
-
3
- ## Overview
4
-
5
- The `@markuplint/i18n` package provides internationalization for markuplint rule messages. It consists of:
6
-
7
- - **Locale dictionaries** (`locales/*.json`) — keywords, sentence templates, and list formatting rules per language
8
- - **Translator engine** (`src/translator.ts`) — resolves templates with keyword substitution, complement forms, and list formatting
9
- - **JSON Schema** (`$schema.json`) — validates locale files with strict property checking
10
-
11
- ### File Structure
12
-
13
- ```
14
- packages/@markuplint/i18n/
15
- ├── locales/
16
- │ ├── ja.json # Japanese dictionary (complete)
17
- │ └── en.json # English dictionary (minimal overrides)
18
- ├── src/
19
- │ ├── translator.ts # Core translation logic
20
- │ ├── types.ts # LocaleSet, Translator types
21
- │ └── index.spec.ts # Test suite
22
- ├── $schema.json # Locale JSON Schema
23
- └── package.json
24
- ```
25
-
26
- ## Three-File Synchronization Rule
27
-
28
- When adding keywords or sentences, three files must be kept in sync:
29
-
30
- | File | Role | Required? |
31
- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------- |
32
- | `$schema.json` | Defines allowed property keys. Uses `additionalProperties: false`, so any key not listed here will cause a validation error. | **Always** |
33
- | `locales/ja.json` | Complete Japanese translations for all keywords and sentences. | **Always** |
34
- | `locales/en.json` | English overrides. Only needed when a keyword requires capitalization or special formatting (e.g., `"html elements"` → `"HTML elements"`). | Only if needed |
35
-
36
- The schema is the source of truth for which keys are valid. If you add a keyword to `ja.json` without adding it to `$schema.json`, the locale file will fail schema validation.
37
-
38
- ## Adding a Keyword
39
-
40
- Keywords are single words or short phrases used as building blocks in rule messages. They appear in the `keywords` section of locale files.
41
-
42
- ### Steps
43
-
44
- 1. **Add to `ja.json`** under `keywords` in alphabetical order:
45
-
46
- ```json
47
- {
48
- "keywords": {
49
- "focusable": "フォーカス可能"
50
- }
51
- }
52
- ```
53
-
54
- - Keys must be lowercase English
55
- - Values are the Japanese translations
56
-
57
- 2. **Add to `en.json`** under `keywords` only if needed:
58
-
59
- ```json
60
- {
61
- "keywords": {
62
- "html elements": "HTML elements"
63
- }
64
- }
65
- ```
66
-
67
- Most English keywords do not need an entry because the key itself is used as-is.
68
-
69
- 3. **Add to `$schema.json`** under `keywords.properties`:
70
-
71
- ```json
72
- {
73
- "keywords": {
74
- "properties": {
75
- "focusable": { "type": "string" }
76
- }
77
- }
78
- }
79
- ```
80
-
81
- 4. **Test**: `yarn test --scope @markuplint/i18n`
82
- 5. **Build**: `yarn build --scope @markuplint/i18n`
83
-
84
- ### Complement Keywords
85
-
86
- Complement keywords use the `c:` prefix and are resolved when a placeholder has the `:c` flag (e.g., `{0:c}`). They form a predicate that attaches to the preceding subject in Japanese.
87
-
88
- | Key in locale | Usage in template | Example output (ja) |
89
- | ---------------------------------------- | -------------------------------------------- | ------------------------------ |
90
- | `"c:deprecated": "は非推奨です"` | `"{0} is {1:c}"` with keyword `"deprecated"` | `「要素」は非推奨です` |
91
- | `"c:disallowed": "は許可されていません"` | `"{0} is {1:c}"` with keyword `"disallowed"` | `「属性」は許可されていません` |
92
- | `"c:prohibited": "は禁止されています"` | `"{0} is {1:c}"` with keyword `"prohibited"` | `「属性」は禁止されています` |
93
-
94
- When adding a complement keyword:
95
-
96
- 1. Add `"c:<word>"` to `ja.json` keywords
97
- 2. Add `"c:<word>"` to `$schema.json` keywords properties
98
- 3. The non-complement version (without `c:`) may also be needed as a separate keyword
99
-
100
- ## Adding a Sentence Template
101
-
102
- Sentence templates define message patterns with placeholders. They appear in the `sentences` section of locale files.
103
-
104
- ### Steps
105
-
106
- 1. **Design the English template** as the key:
107
-
108
- ```
109
- "{0} conflicts with {1}"
110
- ```
111
-
112
- Placeholder syntax:
113
- - `{0}`, `{1}`, `{2}` — positional placeholders, translated as keywords
114
- - `{0:c}` — complement flag, resolves to `c:` prefixed keyword in Japanese
115
- - `{0*}` — no-translate mark, the value is inserted as-is without keyword lookup
116
-
117
- 2. **Add to `ja.json`** under `sentences`:
118
-
119
- ```json
120
- {
121
- "sentences": {
122
- "{0} conflicts with {1}": "{0}は{1}と競合しています"
123
- }
124
- }
125
- ```
126
-
127
- Placeholder order may differ from English to produce natural Japanese.
128
-
129
- 3. **Add to `$schema.json`** under `sentences.properties`:
130
-
131
- ```json
132
- {
133
- "sentences": {
134
- "properties": {
135
- "{0} conflicts with {1}": { "type": "string" }
136
- }
137
- }
138
- }
139
- ```
140
-
141
- 4. **`en.json` does not need a sentences entry**. The English key itself serves as the template. The translator uses the key directly when no translation is found.
142
-
143
- 5. **Test**: `yarn test --scope @markuplint/i18n`
144
-
145
- ### Placeholder Reordering
146
-
147
- Japanese word order differs from English. When translating sentence templates, you can freely reorder placeholders:
148
-
149
- - English: `"{0} is not allowed in {1}"`
150
- - Japanese: `"{1}に{0}は許可されていません"`
151
-
152
- The placeholder numbers refer to the arguments passed to the translator, not their position in the string.
153
-
154
- ## Adding a New Language
155
-
156
- To add support for an entirely new language:
157
-
158
- ### Steps
159
-
160
- 1. **Create `locales/<lang>.json`** using `ja.json` as a template:
161
-
162
- ```json
163
- {
164
- "$schema": "../$schema.json",
165
- "listFormat": {
166
- "quoteStart": "\"",
167
- "quoteEnd": "\"",
168
- "separator": ", "
169
- },
170
- "keywords": {
171
- "attribute": "<translated>",
172
- "element": "<translated>"
173
- },
174
- "sentences": {
175
- "{0} is {1}": "<translated template>"
176
- }
177
- }
178
- ```
179
-
180
- - `listFormat`: Define the quote characters and separators appropriate for the language
181
- - `keywords`: Translate all keywords from `ja.json`
182
- - `sentences`: Translate all sentence templates from `ja.json`
183
-
184
- 2. **Add export entry in `package.json`**:
185
-
186
- ```json
187
- {
188
- "exports": {
189
- "./locales/<lang>.json": {
190
- "import": "./locales/<lang>.json",
191
- "require": "./locales/<lang>.json"
192
- }
193
- }
194
- }
195
- ```
196
-
197
- 3. **`$schema.json` requires no changes** — the schema is shared across all languages.
198
-
199
- 4. **Add test cases** in `src/index.spec.ts` to verify the new locale works correctly with the translator.
200
-
201
- 5. **Test**: `yarn test --scope @markuplint/i18n`
202
-
203
- ## Command Reference
204
-
205
- | Command | Description |
206
- | ------------------------------------- | ----------------- |
207
- | `yarn test --scope @markuplint/i18n` | Run tests |
208
- | `yarn build --scope @markuplint/i18n` | Build the package |