Skip to content

Commit 866e02a

Browse files
committed
feat(i18n): add en.meta.json generation script
1 parent 337a316 commit 866e02a

5 files changed

Lines changed: 109 additions & 27 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
"@storybook/addon-a11y": "catalog:storybook",
128128
"@storybook/addon-docs": "catalog:storybook",
129129
"@storybook/addon-themes": "catalog:storybook",
130+
"@types/dot-object": "2.1.6",
130131
"@types/node": "24.10.13",
131132
"@types/sanitize-html": "2.16.0",
132133
"@types/semver": "7.7.1",

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/i18n-meta/git-utils.ts

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,79 @@
11
import { execSync } from 'node:child_process'
2-
import { relative } from 'node:path'
2+
import * as path from 'node:path'
3+
import * as fs from 'node:fs'
4+
import type { EnJson, EnMetaJson } from './types.d.ts'
35

4-
export function git(command: string): string {
5-
return execSync(command, { encoding: 'utf-8' }).trim()
6+
export function git(command: string) {
7+
try {
8+
return execSync(`git ${command}`, { encoding: 'utf-8' }).trim()
9+
} catch {
10+
console.error(`🚨 Git command failed: git ${command}`)
11+
return null
12+
}
613
}
714

8-
export function getCurrentCommitHash(): string {
9-
return git('git rev-parse HEAD')
15+
function readJson<T>(filePath: string): T {
16+
return JSON.parse(fs.readFileSync(filePath, 'utf-8')) as T
1017
}
1118

12-
export function getPreviousEnJson(fileName: string): string {
13-
const relativePath = relative(process.cwd(), fileName)
14-
return git(`git show HEAD^:${relativePath}`)
19+
export function getCurrentCommitHash() {
20+
return git('rev-parse HEAD')
21+
}
22+
23+
export function getPreviousCommitHash(parsedOldEnMetaJson: EnMetaJson) {
24+
const lastCommit = parsedOldEnMetaJson.$meta?.last_updated_commit
25+
if (lastCommit) {
26+
return lastCommit
27+
}
28+
return git('rev-parse HEAD~1')
29+
}
30+
31+
export function getNewEnJson(enJsonPath: string): EnJson {
32+
if (fs.existsSync(enJsonPath)) {
33+
return readJson<EnMetaJson>(enJsonPath)
34+
}
35+
return {} as EnMetaJson
36+
}
37+
38+
export function getOldEnJson(oldEnMeta: EnMetaJson, enJsonPath: string): EnJson {
39+
const previousHash = getPreviousCommitHash(oldEnMeta)
40+
if (previousHash) {
41+
const relativePath = path.relative(process.cwd(), enJsonPath)
42+
const previousContent = git(`show "${previousHash}:${relativePath}"`)
43+
if (previousContent) {
44+
return JSON.parse(previousContent) as EnMetaJson
45+
}
46+
}
47+
return {} as EnMetaJson
48+
}
49+
50+
export function getOldEnMetaJson(enMetaJsonPath: string): EnMetaJson {
51+
if (fs.existsSync(enMetaJsonPath)) {
52+
return readJson<EnMetaJson>(enMetaJsonPath)
53+
}
54+
return {} as EnMetaJson
55+
}
56+
57+
function omitMeta<T extends object>(obj: T): Omit<T, '$meta'> {
58+
const { $meta: _, ...rest } = obj as T & { $meta?: unknown }
59+
return rest
60+
}
61+
62+
export function checkTranslationChanges(oldMeta: EnMetaJson, newMeta: EnMetaJson): boolean {
63+
const oldObj = omitMeta(oldMeta)
64+
const newObj = omitMeta(newMeta)
65+
return JSON.stringify(oldObj) !== JSON.stringify(newObj)
66+
}
67+
68+
export function createUpdatedEnMetaJson(
69+
commitHash: string | null,
70+
content: EnMetaJson,
71+
): EnMetaJson {
72+
return {
73+
$meta: {
74+
last_updated_commit: commitHash,
75+
updated_at: new Date().toISOString(),
76+
},
77+
...content,
78+
} as EnMetaJson
1579
}

scripts/i18n-meta/types.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,9 @@ export type MetaEntry = {
88
}
99

1010
export type EnMetaJson = {
11+
$meta?: {
12+
last_updated_commit: string
13+
updated_at: string
14+
}
1115
[key: string]: string | MetaEntry | EnMetaJson
1216
}

scripts/i18n-meta/update-en-meta-json.ts

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
1+
import { writeFileSync } from 'node:fs'
22
import { resolve } from 'node:path'
33
import dot from 'dot-object'
4-
import { getCurrentCommitHash, getPreviousEnJson } from './git-utils.ts'
4+
import {
5+
checkTranslationChanges,
6+
createUpdatedEnMetaJson,
7+
getCurrentCommitHash,
8+
getNewEnJson,
9+
getOldEnJson,
10+
getOldEnMetaJson,
11+
} from './git-utils.ts'
512
import type { EnJson, EnMetaJson, MetaEntry } from './types.d.ts'
613

714
const enJsonPath = resolve('i18n/locales/en.json')
@@ -11,29 +18,27 @@ const enMetaJsonPath = resolve('i18n/locales/en.meta.json')
1118
* Update a metadata JSON file for English translations.
1219
*/
1320
export function updateEnMetaJson() {
14-
const newEnJsonRaw = readFileSync(enJsonPath, 'utf-8')
15-
const oldEnJsonRaw = getPreviousEnJson(enJsonPath)
21+
const newEnJson = getNewEnJson(enJsonPath)
22+
const oldEnMetaJson = getOldEnMetaJson(enMetaJsonPath)
23+
const oldEnJson = getOldEnJson(oldEnMetaJson, enJsonPath)
1624

17-
let oldEnMetaJsonRaw = '{}'
18-
if (existsSync(enMetaJsonPath)) {
19-
oldEnMetaJsonRaw = readFileSync(enMetaJsonPath, 'utf-8')
25+
const currentCommitHash = getCurrentCommitHash()
26+
const enMetaJson = currentCommitHash
27+
? makeEnMetaJson(newEnJson, oldEnJson, oldEnMetaJson, currentCommitHash)
28+
: ({} as EnMetaJson)
29+
30+
const hasChanges = checkTranslationChanges(oldEnMetaJson, enMetaJson)
31+
if (!hasChanges) {
32+
console.info('ℹ️ No translation changes – en.meta.json left untouched')
33+
return
2034
}
2135

22-
const latestCommitHash = getCurrentCommitHash()
23-
const enMetaJson = makeEnMetaJson(
24-
JSON.parse(newEnJsonRaw),
25-
JSON.parse(oldEnJsonRaw),
26-
JSON.parse(oldEnMetaJsonRaw),
27-
latestCommitHash,
28-
)
36+
const finalMeta = createUpdatedEnMetaJson(currentCommitHash, enMetaJson)
2937

30-
writeFileSync(enMetaJsonPath, JSON.stringify(enMetaJson, null, 2) + '\n', 'utf-8')
31-
console.log(`📃 Generated ${enMetaJsonPath}`)
38+
writeFileSync(enMetaJsonPath, JSON.stringify(finalMeta, null, 2) + '\n', 'utf-8')
39+
console.log(`✅ Updated en.meta.json – last_updated_commit: ${currentCommitHash}`)
3240
}
3341

34-
/**
35-
* Creates a metadata JSON object by comparing current and previous versions.
36-
*/
3742
export function makeEnMetaJson(
3843
newEnJson: EnJson,
3944
oldEnJson: EnJson,

0 commit comments

Comments
 (0)