Skip to content

Commit e6190db

Browse files
authored
feat: 各ページの翻訳状態の管理機能を実装 (#136)
1 parent 989be0c commit e6190db

File tree

4 files changed

+309
-0
lines changed

4 files changed

+309
-0
lines changed

website/src/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,18 @@ import {
1111
import type { Body, Page } from "./types/model";
1212
import { flattenDocs } from "./utils/flattenDocs";
1313
import { isPageOfKind } from "./utils/isPageOfKind";
14+
import { registerRoutes } from "./utils/translationStatus";
1415

1516
// typst-docsが生成したドキュメント
1617
import docsJson from "../../assets/docs.json";
1718
const docs = docsJson as unknown as Page[];
1819

1920
const [flattenedPages, pagePaths] = flattenDocs(docs);
2021

22+
// 未知のページを未翻訳として登録する
23+
const allRoutes = flattenedPages.map((page) => page.route);
24+
registerRoutes(allRoutes);
25+
2126
const app = new Hono();
2227
app.use(appendTrailingSlash());
2328
app.use(trimTrailingSlash());
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import fs from "node:fs";
2+
import path from "node:path";
3+
4+
export type TranslationStatus =
5+
| "translated"
6+
| "partially_translated"
7+
| "untranslated";
8+
9+
export type TranslationStatusMap = {
10+
[route: string]: TranslationStatus;
11+
};
12+
13+
const TRANSLATION_STATUS_FILE = path.resolve(
14+
process.cwd(),
15+
"translation-status.json",
16+
);
17+
18+
/**
19+
* ページの翻訳状態を管理しているJSONファイルを読み込む。ファイルが存在しない場合は空のオブジェクトを返す。
20+
* @returns ページの翻訳状態を示すオブジェクト。
21+
*/
22+
export const loadTranslationStatus = (): TranslationStatusMap => {
23+
if (fs.existsSync(TRANSLATION_STATUS_FILE)) {
24+
const content = fs.readFileSync(TRANSLATION_STATUS_FILE, "utf-8");
25+
return JSON.parse(content);
26+
}
27+
28+
return {};
29+
};
30+
31+
/**
32+
* ページの翻訳状態を管理しているJSONファイルに書き込む。
33+
* @param status ページの翻訳状態を示すオブジェクト。
34+
*/
35+
export const saveTranslationStatus = (status: TranslationStatusMap): void => {
36+
const json = {
37+
$schema: "./translation-status.schema.json",
38+
...status,
39+
};
40+
fs.writeFileSync(
41+
TRANSLATION_STATUS_FILE,
42+
JSON.stringify(json, null, 2),
43+
"utf-8",
44+
);
45+
};
46+
47+
/**
48+
* 新規ページのルートを未翻訳として登録する。既に登録されているルートは無視される。
49+
* @param routes 登録するページのルートの配列。
50+
*/
51+
export const registerRoutes = (routes: string[]): void => {
52+
const status = loadTranslationStatus();
53+
let changed = false;
54+
55+
for (const route of routes) {
56+
if (!(route in status)) {
57+
status[route] = "untranslated";
58+
changed = true;
59+
}
60+
}
61+
62+
if (changed) {
63+
saveTranslationStatus(status);
64+
}
65+
};
66+
67+
/**
68+
* 翻訳の進捗率を計算する。
69+
* `translated`は1.0、`partially_translated`は0.5の重みを持つ。
70+
* @returns [0.0, 1.0]の範囲で表される翻訳率
71+
*/
72+
export const calculateTranslationProgressRate = (): number => {
73+
const status = loadTranslationStatus();
74+
const routes = Object.keys(status).filter((key) => key !== "$schema");
75+
76+
if (routes.length === 0) {
77+
return 0;
78+
}
79+
80+
let translationScore = 0;
81+
82+
for (const route of routes) {
83+
const currentStatus = status[route];
84+
if (currentStatus === "translated") {
85+
translationScore += 1;
86+
} else if (currentStatus === "partially_translated") {
87+
translationScore += 0.5;
88+
}
89+
}
90+
91+
return translationScore / routes.length;
92+
};

website/translation-status.json

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
{
2+
"$schema": "./translation-status.schema.json",
3+
"/docs/": "translated",
4+
"/docs/tutorial/": "translated",
5+
"/docs/tutorial/writing-in-typst/": "translated",
6+
"/docs/tutorial/formatting/": "translated",
7+
"/docs/tutorial/advanced-styling/": "translated",
8+
"/docs/tutorial/making-a-template/": "translated",
9+
"/docs/reference/": "translated",
10+
"/docs/reference/syntax/": "translated",
11+
"/docs/reference/styling/": "translated",
12+
"/docs/reference/scripting/": "translated",
13+
"/docs/reference/context/": "translated",
14+
"/docs/reference/foundations/": "untranslated",
15+
"/docs/reference/foundations/arguments/": "untranslated",
16+
"/docs/reference/foundations/array/": "untranslated",
17+
"/docs/reference/foundations/assert/": "untranslated",
18+
"/docs/reference/foundations/auto/": "untranslated",
19+
"/docs/reference/foundations/bool/": "untranslated",
20+
"/docs/reference/foundations/bytes/": "untranslated",
21+
"/docs/reference/foundations/calc": "untranslated",
22+
"/docs/reference/foundations/content/": "untranslated",
23+
"/docs/reference/foundations/datetime/": "untranslated",
24+
"/docs/reference/foundations/decimal/": "untranslated",
25+
"/docs/reference/foundations/dictionary/": "untranslated",
26+
"/docs/reference/foundations/duration/": "untranslated",
27+
"/docs/reference/foundations/eval/": "untranslated",
28+
"/docs/reference/foundations/float/": "untranslated",
29+
"/docs/reference/foundations/function/": "untranslated",
30+
"/docs/reference/foundations/int/": "untranslated",
31+
"/docs/reference/foundations/label/": "untranslated",
32+
"/docs/reference/foundations/module/": "untranslated",
33+
"/docs/reference/foundations/none/": "untranslated",
34+
"/docs/reference/foundations/panic/": "untranslated",
35+
"/docs/reference/foundations/plugin/": "untranslated",
36+
"/docs/reference/foundations/regex/": "untranslated",
37+
"/docs/reference/foundations/repr/": "untranslated",
38+
"/docs/reference/foundations/selector/": "untranslated",
39+
"/docs/reference/foundations/str/": "untranslated",
40+
"/docs/reference/foundations/symbol/": "untranslated",
41+
"/docs/reference/foundations/sys": "untranslated",
42+
"/docs/reference/foundations/target/": "untranslated",
43+
"/docs/reference/foundations/type/": "untranslated",
44+
"/docs/reference/foundations/version/": "untranslated",
45+
"/docs/reference/model/": "untranslated",
46+
"/docs/reference/model/bibliography/": "translated",
47+
"/docs/reference/model/list/": "translated",
48+
"/docs/reference/model/cite/": "translated",
49+
"/docs/reference/model/document/": "untranslated",
50+
"/docs/reference/model/emph/": "translated",
51+
"/docs/reference/model/figure/": "translated",
52+
"/docs/reference/model/footnote/": "translated",
53+
"/docs/reference/model/heading/": "untranslated",
54+
"/docs/reference/model/link/": "translated",
55+
"/docs/reference/model/enum/": "translated",
56+
"/docs/reference/model/numbering/": "untranslated",
57+
"/docs/reference/model/outline/": "untranslated",
58+
"/docs/reference/model/par/": "untranslated",
59+
"/docs/reference/model/parbreak/": "untranslated",
60+
"/docs/reference/model/quote/": "untranslated",
61+
"/docs/reference/model/ref/": "translated",
62+
"/docs/reference/model/strong/": "untranslated",
63+
"/docs/reference/model/table/": "untranslated",
64+
"/docs/reference/model/terms/": "untranslated",
65+
"/docs/reference/text/": "untranslated",
66+
"/docs/reference/text/highlight/": "untranslated",
67+
"/docs/reference/text/linebreak/": "untranslated",
68+
"/docs/reference/text/lorem/": "untranslated",
69+
"/docs/reference/text/lower/": "untranslated",
70+
"/docs/reference/text/overline/": "untranslated",
71+
"/docs/reference/text/raw/": "untranslated",
72+
"/docs/reference/text/smallcaps/": "untranslated",
73+
"/docs/reference/text/smartquote/": "untranslated",
74+
"/docs/reference/text/strike/": "untranslated",
75+
"/docs/reference/text/sub/": "untranslated",
76+
"/docs/reference/text/super/": "untranslated",
77+
"/docs/reference/text/text/": "untranslated",
78+
"/docs/reference/text/underline/": "untranslated",
79+
"/docs/reference/text/upper/": "untranslated",
80+
"/docs/reference/math/": "untranslated",
81+
"/docs/reference/math/accent/": "untranslated",
82+
"/docs/reference/math/attach": "untranslated",
83+
"/docs/reference/math/binom/": "untranslated",
84+
"/docs/reference/math/cancel/": "untranslated",
85+
"/docs/reference/math/cases/": "untranslated",
86+
"/docs/reference/math/class/": "untranslated",
87+
"/docs/reference/math/equation/": "untranslated",
88+
"/docs/reference/math/frac/": "untranslated",
89+
"/docs/reference/math/lr": "untranslated",
90+
"/docs/reference/math/mat/": "untranslated",
91+
"/docs/reference/math/primes/": "untranslated",
92+
"/docs/reference/math/roots": "untranslated",
93+
"/docs/reference/math/sizes": "untranslated",
94+
"/docs/reference/math/stretch/": "untranslated",
95+
"/docs/reference/math/styles": "untranslated",
96+
"/docs/reference/math/op/": "untranslated",
97+
"/docs/reference/math/underover": "untranslated",
98+
"/docs/reference/math/variants": "untranslated",
99+
"/docs/reference/math/vec/": "untranslated",
100+
"/docs/reference/symbols/": "untranslated",
101+
"/docs/reference/symbols/sym/": "untranslated",
102+
"/docs/reference/symbols/emoji/": "untranslated",
103+
"/docs/reference/layout/": "untranslated",
104+
"/docs/reference/layout/align/": "untranslated",
105+
"/docs/reference/layout/alignment/": "untranslated",
106+
"/docs/reference/layout/angle/": "untranslated",
107+
"/docs/reference/layout/block/": "untranslated",
108+
"/docs/reference/layout/box/": "untranslated",
109+
"/docs/reference/layout/colbreak/": "untranslated",
110+
"/docs/reference/layout/columns/": "untranslated",
111+
"/docs/reference/layout/direction/": "untranslated",
112+
"/docs/reference/layout/fraction/": "untranslated",
113+
"/docs/reference/layout/grid/": "untranslated",
114+
"/docs/reference/layout/hide/": "untranslated",
115+
"/docs/reference/layout/layout/": "untranslated",
116+
"/docs/reference/layout/length/": "untranslated",
117+
"/docs/reference/layout/measure/": "untranslated",
118+
"/docs/reference/layout/move/": "untranslated",
119+
"/docs/reference/layout/pad/": "untranslated",
120+
"/docs/reference/layout/page/": "untranslated",
121+
"/docs/reference/layout/pagebreak/": "untranslated",
122+
"/docs/reference/layout/place/": "untranslated",
123+
"/docs/reference/layout/ratio/": "untranslated",
124+
"/docs/reference/layout/relative/": "untranslated",
125+
"/docs/reference/layout/repeat/": "untranslated",
126+
"/docs/reference/layout/rotate/": "untranslated",
127+
"/docs/reference/layout/scale/": "untranslated",
128+
"/docs/reference/layout/skew/": "untranslated",
129+
"/docs/reference/layout/h/": "untranslated",
130+
"/docs/reference/layout/v/": "untranslated",
131+
"/docs/reference/layout/stack/": "untranslated",
132+
"/docs/reference/visualize/": "untranslated",
133+
"/docs/reference/visualize/circle/": "untranslated",
134+
"/docs/reference/visualize/color/": "untranslated",
135+
"/docs/reference/visualize/curve/": "untranslated",
136+
"/docs/reference/visualize/ellipse/": "untranslated",
137+
"/docs/reference/visualize/gradient/": "untranslated",
138+
"/docs/reference/visualize/image/": "translated",
139+
"/docs/reference/visualize/line/": "untranslated",
140+
"/docs/reference/visualize/path/": "untranslated",
141+
"/docs/reference/visualize/polygon/": "untranslated",
142+
"/docs/reference/visualize/rect/": "untranslated",
143+
"/docs/reference/visualize/square/": "untranslated",
144+
"/docs/reference/visualize/stroke/": "untranslated",
145+
"/docs/reference/visualize/tiling/": "untranslated",
146+
"/docs/reference/introspection/": "untranslated",
147+
"/docs/reference/introspection/counter/": "untranslated",
148+
"/docs/reference/introspection/here/": "untranslated",
149+
"/docs/reference/introspection/locate/": "untranslated",
150+
"/docs/reference/introspection/location/": "untranslated",
151+
"/docs/reference/introspection/metadata/": "untranslated",
152+
"/docs/reference/introspection/query/": "untranslated",
153+
"/docs/reference/introspection/state/": "untranslated",
154+
"/docs/reference/data-loading/": "untranslated",
155+
"/docs/reference/data-loading/cbor/": "untranslated",
156+
"/docs/reference/data-loading/csv/": "untranslated",
157+
"/docs/reference/data-loading/json/": "untranslated",
158+
"/docs/reference/data-loading/read/": "untranslated",
159+
"/docs/reference/data-loading/toml/": "untranslated",
160+
"/docs/reference/data-loading/xml/": "untranslated",
161+
"/docs/reference/data-loading/yaml/": "untranslated",
162+
"/docs/reference/pdf/": "untranslated",
163+
"/docs/reference/pdf/embed/": "untranslated",
164+
"/docs/reference/html/": "untranslated",
165+
"/docs/reference/html/elem/": "untranslated",
166+
"/docs/reference/html/frame/": "untranslated",
167+
"/docs/reference/png/": "untranslated",
168+
"/docs/reference/svg/": "untranslated",
169+
"/docs/guides/": "untranslated",
170+
"/docs/guides/guide-for-latex-users/": "untranslated",
171+
"/docs/guides/page-setup-guide/": "untranslated",
172+
"/docs/guides/table-guide/": "untranslated",
173+
"/docs/changelog/": "untranslated",
174+
"/docs/changelog/0.13.1/": "untranslated",
175+
"/docs/changelog/0.13.0/": "untranslated",
176+
"/docs/changelog/0.12.0/": "untranslated",
177+
"/docs/changelog/0.11.1/": "untranslated",
178+
"/docs/changelog/0.11.0/": "untranslated",
179+
"/docs/changelog/0.10.0/": "untranslated",
180+
"/docs/changelog/0.9.0/": "untranslated",
181+
"/docs/changelog/0.8.0/": "untranslated",
182+
"/docs/changelog/0.7.0/": "untranslated",
183+
"/docs/changelog/0.6.0/": "untranslated",
184+
"/docs/changelog/0.5.0/": "untranslated",
185+
"/docs/changelog/0.4.0/": "untranslated",
186+
"/docs/changelog/0.3.0/": "untranslated",
187+
"/docs/changelog/0.2.0/": "untranslated",
188+
"/docs/changelog/0.1.0/": "untranslated",
189+
"/docs/changelog/earlier/": "untranslated",
190+
"/docs/japanese/": "translated",
191+
"/docs/japanese/templates/": "translated",
192+
"/docs/japanese/packages/": "translated",
193+
"/docs/japanese/articles/": "translated",
194+
"/docs/glossary/": "translated"
195+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"title": "ページの翻訳状態",
4+
"description": "各ページの翻訳状態を管理するためのJSONファイル",
5+
"type": "object",
6+
"properties": {
7+
"$schema": {
8+
"type": "string",
9+
"description": "このJSONファイルで使用されるJSONスキーマへの参照"
10+
}
11+
},
12+
"additionalProperties": {
13+
"type": "string",
14+
"enum": ["translated", "partially_translated", "untranslated"],
15+
"description": "ページの翻訳状態"
16+
}
17+
}

0 commit comments

Comments
 (0)