fix(i18n): i18n key should can nested
Signed-off-by: Innei <i@innei.in>
This commit is contained in:
parent
34b9a20acf
commit
98e899df09
|
|
@ -82,7 +82,7 @@ export const SettingLists = () => {
|
|||
{t.settings("lists.view")}
|
||||
</TableHead>
|
||||
<TableHead className="w-20" size="sm">
|
||||
{t.settings("lists.fee")}
|
||||
{t.settings("lists.fee.label")}
|
||||
</TableHead>
|
||||
|
||||
<TableHead className="w-20" size="sm">
|
||||
|
|
@ -147,7 +147,7 @@ export const SettingLists = () => {
|
|||
variant="ghost"
|
||||
onClick={() => {
|
||||
present({
|
||||
title: t.settings("lists.edit"),
|
||||
title: t.settings("lists.edit.label"),
|
||||
content: ({ dismiss }) => (
|
||||
<ListCreationModalContent dismiss={dismiss} id={row.id} />
|
||||
),
|
||||
|
|
@ -314,7 +314,7 @@ const ListCreationModalContent = ({ dismiss, id }: { dismiss: () => void; id?: s
|
|||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<div>
|
||||
<FormLabel>{t("lists.fee")}</FormLabel>
|
||||
<FormLabel>{t("lists.fee.label")}</FormLabel>
|
||||
<FormDescription>{t("lists.fee.description")}</FormDescription>
|
||||
</div>
|
||||
<FormControl>
|
||||
|
|
@ -434,7 +434,7 @@ export const ListFeedsModalContent = ({ id }: { id: string }) => {
|
|||
}
|
||||
}}
|
||||
>
|
||||
{t("lists.feeds.add")}
|
||||
{t("lists.feeds.add.label")}
|
||||
</Button>
|
||||
</div>
|
||||
<Divider className="mt-8" />
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// @ts-check
|
||||
import { defineConfig } from "eslint-config-hyoban"
|
||||
|
||||
import checkI18nJson from "./plugins/eslint-check-i18n-json.js"
|
||||
import recursiveSort from "./plugins/eslint-recursive-sort.js"
|
||||
|
||||
export default defineConfig(
|
||||
|
|
@ -49,9 +50,11 @@ export default defineConfig(
|
|||
files: ["locales/**/*.json"],
|
||||
plugins: {
|
||||
"recursive-sort": recursiveSort,
|
||||
"check-i18n-json": checkI18nJson,
|
||||
},
|
||||
rules: {
|
||||
"recursive-sort/recursive-sort": "error",
|
||||
"check-i18n-json/valid-i18n-keys": "error",
|
||||
},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -156,19 +156,19 @@
|
|||
"lists.created.error": "Failed to create list.",
|
||||
"lists.created.success": "List created successfully!",
|
||||
"lists.description": "Description",
|
||||
"lists.edit": "Edit",
|
||||
"lists.edit.error": "Failed to edit list.",
|
||||
"lists.edit.label": "Edit",
|
||||
"lists.edit.success": "List edited successfully!",
|
||||
"lists.fee": "Fee",
|
||||
"lists.fee.description": "The fee others need to pay you to subscribe to this list.",
|
||||
"lists.feeds": "Feeds",
|
||||
"lists.fee.label": "Fee",
|
||||
"lists.feeds.actions": "Actions",
|
||||
"lists.feeds.add": "Add",
|
||||
"lists.feeds.add.error": "Failed to add feed to list.",
|
||||
"lists.feeds.add.label": "Add",
|
||||
"lists.feeds.add.success": "Feed added to list.",
|
||||
"lists.feeds.delete.error": "Failed to remove feed from list.",
|
||||
"lists.feeds.delete.success": "Feed removed from list.",
|
||||
"lists.feeds.id": "Feed ID",
|
||||
"lists.feeds.label": "Feeds",
|
||||
"lists.feeds.manage": "Manage Feeds",
|
||||
"lists.feeds.owner": "Owner",
|
||||
"lists.feeds.search": "Search for feed",
|
||||
|
|
@ -234,4 +234,4 @@
|
|||
"wallet.withdraw.modalTitle": "Withdraw Power",
|
||||
"wallet.withdraw.submitButton": "Submit",
|
||||
"wallet.withdraw.success": "Withdrawal successful!"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,19 +156,19 @@
|
|||
"lists.created.error": "목록 생성에 실패했습니다.",
|
||||
"lists.created.success": "목록이 성공적으로 생성되었습니다!",
|
||||
"lists.description": "설명",
|
||||
"lists.edit": "편집",
|
||||
"lists.edit.error": "목록 편집에 실패했습니다.",
|
||||
"lists.edit.label": "편집",
|
||||
"lists.edit.success": "목록이 성공적으로 편집되었습니다!",
|
||||
"lists.fee": "수수료",
|
||||
"lists.fee.description": "다른 사용자가 이 목록을 구독하려면 지불해야 하는 비용입니다.",
|
||||
"lists.feeds": "피드",
|
||||
"lists.fee.label": "수수료",
|
||||
"lists.feeds.actions": "액션",
|
||||
"lists.feeds.add": "추가",
|
||||
"lists.feeds.add.error": "목록에 피드를 추가하지 못했습니다.",
|
||||
"lists.feeds.add.label": "추가",
|
||||
"lists.feeds.add.success": "피드가 목록에 추가되었습니다.",
|
||||
"lists.feeds.delete.error": "목록에서 피드를 제거하지 못했습니다.",
|
||||
"lists.feeds.delete.success": "목록에서 피드가 제거되었습니다.",
|
||||
"lists.feeds.id": "피드 ID",
|
||||
"lists.feeds.label": "피드",
|
||||
"lists.feeds.manage": "피드 관리",
|
||||
"lists.feeds.owner": "소유자",
|
||||
"lists.feeds.search": "피드 검색",
|
||||
|
|
@ -234,4 +234,4 @@
|
|||
"wallet.withdraw.modalTitle": "파워 인출",
|
||||
"wallet.withdraw.submitButton": "제출",
|
||||
"wallet.withdraw.success": "인출이 성공적으로 완료되었습니다!"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,19 +156,19 @@
|
|||
"lists.created.error": "创建列表失败",
|
||||
"lists.created.success": "创建列表成功",
|
||||
"lists.description": "描述",
|
||||
"lists.edit": "编辑",
|
||||
"lists.edit.error": "编辑列表失败",
|
||||
"lists.edit.label": "编辑",
|
||||
"lists.edit.success": "编辑列表成功",
|
||||
"lists.fee": "费用",
|
||||
"lists.fee.description": "其他人订阅这个列表时要支付的费用",
|
||||
"lists.feeds": "订阅源",
|
||||
"lists.fee.label": "费用",
|
||||
"lists.feeds.actions": "自动化",
|
||||
"lists.feeds.add": "添加",
|
||||
"lists.feeds.add.error": "添加订阅源到列表时失败",
|
||||
"lists.feeds.add.label": "添加",
|
||||
"lists.feeds.add.success": "订阅源已添加到列表",
|
||||
"lists.feeds.delete.error": "添加订阅源到列表时失败",
|
||||
"lists.feeds.delete.success": "订阅源已从列表删除",
|
||||
"lists.feeds.id": "订阅源 ID",
|
||||
"lists.feeds.label": "订阅源",
|
||||
"lists.feeds.manage": "管理订阅源",
|
||||
"lists.feeds.owner": "所有者",
|
||||
"lists.feeds.search": "搜索订阅源",
|
||||
|
|
@ -234,4 +234,4 @@
|
|||
"wallet.withdraw.modalTitle": "提现 Power",
|
||||
"wallet.withdraw.submitButton": "提交",
|
||||
"wallet.withdraw.success": "提现成功!"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
import path from "node:path"
|
||||
|
||||
/** @type {import("eslint").ESLint.Plugin} */
|
||||
export default {
|
||||
rules: {
|
||||
"valid-i18n-keys": {
|
||||
meta: {
|
||||
type: "problem",
|
||||
docs: {
|
||||
description: "Ensure i18n JSON keys are flat and valid as object paths",
|
||||
category: "Possible Errors",
|
||||
recommended: true,
|
||||
},
|
||||
fixable: null,
|
||||
},
|
||||
create(context) {
|
||||
return {
|
||||
Program(node) {
|
||||
const filename = context.getFilename()
|
||||
if (path.basename(filename) !== "en.json") return
|
||||
|
||||
const sourceCode = context.getSourceCode()
|
||||
let json
|
||||
try {
|
||||
json = JSON.parse(sourceCode.text)
|
||||
} catch {
|
||||
context.report({
|
||||
node,
|
||||
message: "Invalid JSON format",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const keys = Object.keys(json)
|
||||
const keyPrefixes = new Set()
|
||||
|
||||
for (const key of keys) {
|
||||
if (key.includes(".")) {
|
||||
const parts = key.split(".")
|
||||
for (let i = 1; i < parts.length; i++) {
|
||||
const prefix = parts.slice(0, i).join(".")
|
||||
if (keys.includes(prefix)) {
|
||||
context.report({
|
||||
node,
|
||||
message: `Invalid key structure: '${key}' conflicts with '${prefix}'`,
|
||||
})
|
||||
}
|
||||
keyPrefixes.add(prefix)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of keys) {
|
||||
if (keyPrefixes.has(key)) {
|
||||
context.report({
|
||||
node,
|
||||
message: `Invalid key structure: '${key}' is a prefix of another key`,
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
Loading…
Reference in New Issue