mirror of
https://github.com/reonokiy/blog.nokiy.net.git
synced 2025-06-15 11:12:54 +02:00
refactor: optimize multilingual article routing logic, modify slug to abbrlink
This commit is contained in:
parent
16491dae50
commit
e5165dd740
16 changed files with 673 additions and 133 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -59,6 +59,7 @@
|
|||
"*.mdx": "markdown"
|
||||
},
|
||||
"cSpell.words": [
|
||||
"abbrlink",
|
||||
"antfu",
|
||||
"Artículos",
|
||||
"astrojs",
|
||||
|
|
142
pnpm-lock.yaml
generated
142
pnpm-lock.yaml
generated
|
@ -95,7 +95,7 @@ importers:
|
|||
devDependencies:
|
||||
'@antfu/eslint-config':
|
||||
specifier: ^4.8.1
|
||||
version: 4.8.1(@typescript-eslint/utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(@unocss/eslint-plugin@66.1.0-beta.3(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(@vue/compiler-sfc@3.5.13)(astro-eslint-parser@1.2.1)(eslint-plugin-astro@1.3.1(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
version: 4.8.1(@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(@unocss/eslint-plugin@66.1.0-beta.3(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(@vue/compiler-sfc@3.5.13)(astro-eslint-parser@1.2.1)(eslint-plugin-astro@1.3.1(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@types/markdown-it':
|
||||
specifier: ^14.1.2
|
||||
version: 14.1.2
|
||||
|
@ -937,51 +937,51 @@ packages:
|
|||
'@types/web-bluetooth@0.0.21':
|
||||
resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.26.0':
|
||||
resolution: {integrity: sha512-cLr1J6pe56zjKYajK6SSSre6nl1Gj6xDp1TY0trpgPzjVbgDwd09v2Ws37LABxzkicmUjhEeg/fAUjPJJB1v5Q==}
|
||||
'@typescript-eslint/eslint-plugin@8.26.1':
|
||||
resolution: {integrity: sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/parser@8.26.0':
|
||||
resolution: {integrity: sha512-mNtXP9LTVBy14ZF3o7JG69gRPBK/2QWtQd0j0oH26HcY/foyJJau6pNUez7QrM5UHnSvwlQcJXKsk0I99B9pOA==}
|
||||
'@typescript-eslint/parser@8.26.1':
|
||||
resolution: {integrity: sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/scope-manager@8.26.0':
|
||||
resolution: {integrity: sha512-E0ntLvsfPqnPwng8b8y4OGuzh/iIOm2z8U3S9zic2TeMLW61u5IH2Q1wu0oSTkfrSzwbDJIB/Lm8O3//8BWMPA==}
|
||||
'@typescript-eslint/scope-manager@8.26.1':
|
||||
resolution: {integrity: sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/type-utils@8.26.0':
|
||||
resolution: {integrity: sha512-ruk0RNChLKz3zKGn2LwXuVoeBcUMh+jaqzN461uMMdxy5H9epZqIBtYj7UiPXRuOpaALXGbmRuZQhmwHhaS04Q==}
|
||||
'@typescript-eslint/type-utils@8.26.1':
|
||||
resolution: {integrity: sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/types@8.26.0':
|
||||
resolution: {integrity: sha512-89B1eP3tnpr9A8L6PZlSjBvnJhWXtYfZhECqlBl1D9Lme9mHO6iWlsprBtVenQvY1HMhax1mWOjhtL3fh/u+pA==}
|
||||
'@typescript-eslint/types@8.26.1':
|
||||
resolution: {integrity: sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.26.0':
|
||||
resolution: {integrity: sha512-tiJ1Hvy/V/oMVRTbEOIeemA2XoylimlDQ03CgPPNaHYZbpsc78Hmngnt+WXZfJX1pjQ711V7g0H7cSJThGYfPQ==}
|
||||
'@typescript-eslint/typescript-estree@8.26.1':
|
||||
resolution: {integrity: sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/utils@8.26.0':
|
||||
resolution: {integrity: sha512-2L2tU3FVwhvU14LndnQCA2frYC8JnPDVKyQtWFPf8IYFMt/ykEN1bPolNhNbCVgOmdzTlWdusCTKA/9nKrf8Ig==}
|
||||
'@typescript-eslint/utils@8.26.1':
|
||||
resolution: {integrity: sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: '>=4.8.4 <5.9.0'
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.26.0':
|
||||
resolution: {integrity: sha512-2z8JQJWAzPdDd51dRQ/oqIJxe99/hoLIqmf8RMCAJQtYDc535W/Jt2+RTP4bP0aKeBG1F65yjIZuczOXCmbWwg==}
|
||||
'@typescript-eslint/visitor-keys@8.26.1':
|
||||
resolution: {integrity: sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
|
||||
'@ungap/structured-clone@1.3.0':
|
||||
|
@ -1731,8 +1731,8 @@ packages:
|
|||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
|
||||
eslint-plugin-jsdoc@50.6.3:
|
||||
resolution: {integrity: sha512-NxbJyt1M5zffPcYZ8Nb53/8nnbIScmiLAMdoe0/FAszwb7lcSiX3iYBTsuF7RV84dZZJC8r3NghomrUXsmWvxQ==}
|
||||
eslint-plugin-jsdoc@50.6.5:
|
||||
resolution: {integrity: sha512-SNvAP/xdq5caeS3T5dZzBqtuYNmaXpG2F1I3+HKf2Csd0C/F6MoxQQ5NiX1nk9WhiZGhpZhfxqJkOfc36HRrAQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
eslint: ^7.0.0 || ^8.0.0 || ^9.0.0
|
||||
|
@ -2887,8 +2887,8 @@ packages:
|
|||
engines: {node: '>=10.13.0'}
|
||||
hasBin: true
|
||||
|
||||
prismjs@1.29.0:
|
||||
resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
|
||||
prismjs@1.30.0:
|
||||
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
prompts@2.4.2:
|
||||
|
@ -3809,16 +3809,16 @@ snapshots:
|
|||
'@jridgewell/gen-mapping': 0.3.8
|
||||
'@jridgewell/trace-mapping': 0.3.25
|
||||
|
||||
'@antfu/eslint-config@4.8.1(@typescript-eslint/utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(@unocss/eslint-plugin@66.1.0-beta.3(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(@vue/compiler-sfc@3.5.13)(astro-eslint-parser@1.2.1)(eslint-plugin-astro@1.3.1(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
'@antfu/eslint-config@4.8.1(@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(@unocss/eslint-plugin@66.1.0-beta.3(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(@vue/compiler-sfc@3.5.13)(astro-eslint-parser@1.2.1)(eslint-plugin-astro@1.3.1(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@antfu/install-pkg': 1.0.0
|
||||
'@clack/prompts': 0.10.0
|
||||
'@eslint-community/eslint-plugin-eslint-comments': 4.4.1(eslint@9.22.0(jiti@2.4.2))
|
||||
'@eslint/markdown': 6.3.0
|
||||
'@stylistic/eslint-plugin': 4.2.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@vitest/eslint-plugin': 1.1.36(@typescript-eslint/utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@vitest/eslint-plugin': 1.1.36(@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
ansis: 3.17.0
|
||||
cac: 6.7.14
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
|
@ -3828,7 +3828,7 @@ snapshots:
|
|||
eslint-plugin-antfu: 3.1.1(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-command: 3.1.0(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-import-x: 4.6.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
eslint-plugin-jsdoc: 50.6.3(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-jsdoc: 50.6.5(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-jsonc: 2.19.1(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-n: 17.16.2(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-no-only-tests: 3.3.0
|
||||
|
@ -3837,7 +3837,7 @@ snapshots:
|
|||
eslint-plugin-regexp: 2.7.0(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-toml: 0.12.0(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-unicorn: 57.0.0(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-unused-imports: 4.1.4(@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-unused-imports: 4.1.4(@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-plugin-vue: 10.0.0(eslint@9.22.0(jiti@2.4.2))(vue-eslint-parser@10.1.1(eslint@9.22.0(jiti@2.4.2)))
|
||||
eslint-plugin-yml: 1.17.0(eslint@9.22.0(jiti@2.4.2))
|
||||
eslint-processor-vue-blocks: 2.0.0(@vue/compiler-sfc@3.5.13)(eslint@9.22.0(jiti@2.4.2))
|
||||
|
@ -3957,7 +3957,7 @@ snapshots:
|
|||
|
||||
'@astrojs/prism@3.2.0':
|
||||
dependencies:
|
||||
prismjs: 1.29.0
|
||||
prismjs: 1.30.0
|
||||
|
||||
'@astrojs/rss@4.0.11':
|
||||
dependencies:
|
||||
|
@ -4054,7 +4054,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@types/eslint': 9.6.1
|
||||
'@types/estree': 1.0.6
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
comment-parser: 1.4.1
|
||||
esquery: 1.6.0
|
||||
jsdoc-type-pratt-parser: 4.1.0
|
||||
|
@ -4489,7 +4489,7 @@ snapshots:
|
|||
|
||||
'@stylistic/eslint-plugin@4.2.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
eslint-visitor-keys: 4.2.0
|
||||
espree: 10.3.0
|
||||
|
@ -4587,14 +4587,14 @@ snapshots:
|
|||
|
||||
'@types/web-bluetooth@0.0.21': {}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
'@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.1
|
||||
'@typescript-eslint/parser': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/scope-manager': 8.26.0
|
||||
'@typescript-eslint/type-utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/visitor-keys': 8.26.0
|
||||
'@typescript-eslint/parser': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/scope-manager': 8.26.1
|
||||
'@typescript-eslint/type-utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/visitor-keys': 8.26.1
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
graphemer: 1.4.0
|
||||
ignore: 5.3.2
|
||||
|
@ -4604,27 +4604,27 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
'@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.26.0
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2)
|
||||
'@typescript-eslint/visitor-keys': 8.26.0
|
||||
'@typescript-eslint/scope-manager': 8.26.1
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
|
||||
'@typescript-eslint/visitor-keys': 8.26.1
|
||||
debug: 4.4.0
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
typescript: 5.8.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/scope-manager@8.26.0':
|
||||
'@typescript-eslint/scope-manager@8.26.1':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/visitor-keys': 8.26.0
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
'@typescript-eslint/visitor-keys': 8.26.1
|
||||
|
||||
'@typescript-eslint/type-utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
'@typescript-eslint/type-utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
debug: 4.4.0
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
ts-api-utils: 2.0.1(typescript@5.8.2)
|
||||
|
@ -4632,12 +4632,12 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/types@8.26.0': {}
|
||||
'@typescript-eslint/types@8.26.1': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@8.26.0(typescript@5.8.2)':
|
||||
'@typescript-eslint/typescript-estree@8.26.1(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/visitor-keys': 8.26.0
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
'@typescript-eslint/visitor-keys': 8.26.1
|
||||
debug: 4.4.0
|
||||
fast-glob: 3.3.3
|
||||
is-glob: 4.0.3
|
||||
|
@ -4648,20 +4648,20 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
'@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2))
|
||||
'@typescript-eslint/scope-manager': 8.26.0
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/typescript-estree': 8.26.0(typescript@5.8.2)
|
||||
'@typescript-eslint/scope-manager': 8.26.1
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
'@typescript-eslint/typescript-estree': 8.26.1(typescript@5.8.2)
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
typescript: 5.8.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/visitor-keys@8.26.0':
|
||||
'@typescript-eslint/visitor-keys@8.26.1':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
eslint-visitor-keys: 4.2.0
|
||||
|
||||
'@ungap/structured-clone@1.3.0': {}
|
||||
|
@ -4703,7 +4703,7 @@ snapshots:
|
|||
|
||||
'@unocss/eslint-plugin@66.1.0-beta.3(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@unocss/config': 66.1.0-beta.3
|
||||
'@unocss/core': 66.1.0-beta.3
|
||||
'@unocss/rule-utils': 66.1.0-beta.3
|
||||
|
@ -4837,9 +4837,9 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- vue
|
||||
|
||||
'@vitest/eslint-plugin@1.1.36(@typescript-eslint/utils@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
'@vitest/eslint-plugin@1.1.36(@typescript-eslint/utils@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)':
|
||||
dependencies:
|
||||
'@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
optionalDependencies:
|
||||
typescript: 5.8.2
|
||||
|
@ -5091,8 +5091,8 @@ snapshots:
|
|||
astro-eslint-parser@1.2.1:
|
||||
dependencies:
|
||||
'@astrojs/compiler': 2.10.4
|
||||
'@typescript-eslint/scope-manager': 8.26.0
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/scope-manager': 8.26.1
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
astrojs-compiler-sync: 1.0.1(@astrojs/compiler@2.10.4)
|
||||
debug: 4.4.0
|
||||
entities: 6.0.0
|
||||
|
@ -5629,7 +5629,7 @@ snapshots:
|
|||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.1(eslint@9.22.0(jiti@2.4.2))
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
astro-eslint-parser: 1.2.1
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
eslint-compat-utils: 0.6.4(eslint@9.22.0(jiti@2.4.2))
|
||||
|
@ -5654,8 +5654,8 @@ snapshots:
|
|||
eslint-plugin-import-x@4.6.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
|
||||
dependencies:
|
||||
'@types/doctrine': 0.0.9
|
||||
'@typescript-eslint/scope-manager': 8.26.0
|
||||
'@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/scope-manager': 8.26.1
|
||||
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
debug: 4.4.0
|
||||
doctrine: 3.0.0
|
||||
enhanced-resolve: 5.18.1
|
||||
|
@ -5671,7 +5671,7 @@ snapshots:
|
|||
- supports-color
|
||||
- typescript
|
||||
|
||||
eslint-plugin-jsdoc@50.6.3(eslint@9.22.0(jiti@2.4.2)):
|
||||
eslint-plugin-jsdoc@50.6.5(eslint@9.22.0(jiti@2.4.2)):
|
||||
dependencies:
|
||||
'@es-joy/jsdoccomment': 0.49.0
|
||||
are-docs-informative: 0.0.2
|
||||
|
@ -5718,8 +5718,8 @@ snapshots:
|
|||
|
||||
eslint-plugin-perfectionist@4.10.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2):
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.26.0
|
||||
'@typescript-eslint/utils': 8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/types': 8.26.1
|
||||
'@typescript-eslint/utils': 8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
natural-orderby: 5.0.0
|
||||
transitivePeerDependencies:
|
||||
|
@ -5774,11 +5774,11 @@ snapshots:
|
|||
semver: 7.7.1
|
||||
strip-indent: 4.0.0
|
||||
|
||||
eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)):
|
||||
eslint-plugin-unused-imports@4.1.4(@typescript-eslint/eslint-plugin@8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2)):
|
||||
dependencies:
|
||||
eslint: 9.22.0(jiti@2.4.2)
|
||||
optionalDependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.26.0(@typescript-eslint/parser@8.26.0(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
'@typescript-eslint/eslint-plugin': 8.26.1(@typescript-eslint/parser@8.26.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2))(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.2)
|
||||
|
||||
eslint-plugin-vue@10.0.0(eslint@9.22.0(jiti@2.4.2))(vue-eslint-parser@10.1.1(eslint@9.22.0(jiti@2.4.2))):
|
||||
dependencies:
|
||||
|
@ -7275,7 +7275,7 @@ snapshots:
|
|||
prettier@2.8.7:
|
||||
optional: true
|
||||
|
||||
prismjs@1.29.0: {}
|
||||
prismjs@1.30.0: {}
|
||||
|
||||
prompts@2.4.2:
|
||||
dependencies:
|
||||
|
|
|
@ -2,22 +2,22 @@
|
|||
// Define props received by the component
|
||||
interface Post {
|
||||
data: {
|
||||
title: string;
|
||||
slug?: string;
|
||||
published: Date;
|
||||
};
|
||||
slug?: string;
|
||||
title: string
|
||||
abbrlink?: string
|
||||
published: Date
|
||||
}
|
||||
slug?: string
|
||||
remarkPluginFrontmatter?: {
|
||||
minutes?: number;
|
||||
};
|
||||
minutes?: number
|
||||
}
|
||||
}
|
||||
|
||||
// Receive posts parameter passed from outside
|
||||
const { posts } = Astro.props;
|
||||
const { posts } = Astro.props
|
||||
|
||||
// Declare the type of props
|
||||
export interface Props {
|
||||
posts: Post[];
|
||||
posts: Post[]
|
||||
}
|
||||
---
|
||||
<ul>
|
||||
|
@ -27,8 +27,8 @@ export interface Props {
|
|||
|
||||
<a
|
||||
class="hover:c-primary"
|
||||
href={`/posts/${post.data.slug || post.slug}`}
|
||||
transition:name={`post-${post.data.slug || post.slug}`}
|
||||
href={`/posts/${post.data.abbrlink || post.slug}/`}
|
||||
transition:name={`post-${post.data.abbrlink || post.slug}`}
|
||||
data-disable-transition-on-theme
|
||||
>
|
||||
{post.data.title}
|
||||
|
@ -36,7 +36,7 @@ export interface Props {
|
|||
|
||||
<div
|
||||
class="uno-mobile-time"
|
||||
transition:name={`time-${post.data.slug || post.slug}`}
|
||||
transition:name={`time-${post.data.abbrlink || post.slug}`}
|
||||
data-disable-transition-on-theme
|
||||
>
|
||||
<time>
|
||||
|
|
|
@ -1,14 +1,64 @@
|
|||
---
|
||||
import themeConfig from '@/config'
|
||||
import { getPagePath } from '@/utils/i18n/path'
|
||||
import { getCollection } from 'astro:content'
|
||||
|
||||
// Language array with empty string as default locale
|
||||
const langs = ['', ...themeConfig.global.moreLocale]
|
||||
const currentLocale = themeConfig.global.locale
|
||||
// 获取当前页面路径信息
|
||||
const { isPost } = getPagePath(Astro.url.pathname)
|
||||
|
||||
function getLanguageDisplayName(code: string) {
|
||||
if (!code) {
|
||||
return 'Default'
|
||||
// 获取默认语言
|
||||
const defaultLocale = themeConfig.global.locale
|
||||
|
||||
// 定义固定的语言顺序(按照要求的顺序)
|
||||
const fixedLangOrder = [defaultLocale, ...themeConfig.global.moreLocale]
|
||||
|
||||
// 获取当前文章的可用语言
|
||||
let availableLangs: string[] = []
|
||||
let currentPostSlug = ''
|
||||
|
||||
// 如果是文章页,获取当前文章对象
|
||||
if (isPost) {
|
||||
// 从URL中提取文章slug
|
||||
const pathParts = Astro.url.pathname.split('/')
|
||||
const slugIndex = pathParts.findIndex(part => part === 'posts') + 1
|
||||
if (slugIndex > 0 && pathParts.length > slugIndex) {
|
||||
currentPostSlug = pathParts[slugIndex]
|
||||
|
||||
// 获取所有文章
|
||||
const posts = await getCollection('posts')
|
||||
|
||||
// 找到所有具有相同abbrlink或slug的文章
|
||||
const relatedPosts = posts.filter(post =>
|
||||
post.data.abbrlink === currentPostSlug || post.slug === currentPostSlug,
|
||||
)
|
||||
|
||||
if (relatedPosts.length > 0) {
|
||||
// 收集所有相关文章支持的语言
|
||||
const supportedLangs = new Set()
|
||||
|
||||
relatedPosts.forEach((post) => {
|
||||
// 处理lang属性
|
||||
if (typeof post.data.lang === 'string' && post.data.lang.trim() !== '') {
|
||||
supportedLangs.add(post.data.lang)
|
||||
}
|
||||
// 如果没有指定语言,则假定支持默认语言
|
||||
else {
|
||||
supportedLangs.add(defaultLocale)
|
||||
}
|
||||
})
|
||||
|
||||
// 按照固定顺序筛选出可用的语言
|
||||
availableLangs = fixedLangOrder.filter(lang => supportedLangs.has(lang))
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 非文章页面使用所有语言
|
||||
availableLangs = fixedLangOrder
|
||||
}
|
||||
|
||||
// 当前语言
|
||||
function getLanguageDisplayName(code: string) {
|
||||
return new Intl.DisplayNames(['en'], { type: 'language' }).of(code) || code
|
||||
}
|
||||
---
|
||||
|
@ -17,7 +67,7 @@ function getLanguageDisplayName(code: string) {
|
|||
type="button"
|
||||
id="language-switcher"
|
||||
class="aspect-square w-4 c-secondary active:scale-90"
|
||||
aria-label={`Current Language: ${getLanguageDisplayName(currentLocale)}. Click to switch to next language.`}
|
||||
aria-label={`Current Language: ${getLanguageDisplayName(defaultLocale)}. Click to switch to next language.`}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
@ -29,7 +79,7 @@ function getLanguageDisplayName(code: string) {
|
|||
</svg>
|
||||
</button>
|
||||
|
||||
<script is:inline define:vars={{ langs }}>
|
||||
<script is:inline define:vars={{ availableLangs, currentPostSlug, isPost, defaultLocale }}>
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
const langSwitch = document.getElementById('language-switcher')
|
||||
|
||||
|
@ -38,30 +88,53 @@ document.addEventListener('astro:page-load', () => {
|
|||
const segments = pathname.split('/').filter(Boolean)
|
||||
const firstSegment = segments[0] || ''
|
||||
|
||||
// Get current language or empty string if invalid
|
||||
const currentLang = langs.includes(firstSegment)
|
||||
? firstSegment
|
||||
: ''
|
||||
// 获取当前语言
|
||||
let currentLang = defaultLocale
|
||||
if (availableLangs.includes(firstSegment) && firstSegment !== defaultLocale) {
|
||||
currentLang = firstSegment
|
||||
}
|
||||
|
||||
const currentIndex = langs.indexOf(currentLang)
|
||||
const nextLang = langs[(currentIndex + 1) % langs.length]
|
||||
// 获取下一个语言
|
||||
const currentIndex = availableLangs.indexOf(currentLang)
|
||||
const nextLang = availableLangs[(currentIndex + 1) % availableLangs.length]
|
||||
|
||||
const newPath = buildNewPath(currentLang, nextLang, segments, pathname) || '/'
|
||||
const newPath = buildNewPath(currentLang, nextLang, segments) || '/'
|
||||
window.location.href = `${newPath}${search}${hash}`
|
||||
})
|
||||
})
|
||||
|
||||
function buildNewPath(currentLang, nextLang, segments, pathname) {
|
||||
if (currentLang) {
|
||||
segments[0] = nextLang || segments[0]
|
||||
function buildNewPath(currentLang, nextLang, segments) {
|
||||
// 创建一个新的segments数组副本,避免修改原始数组
|
||||
const newSegments = [...segments]
|
||||
const firstSegment = newSegments[0] || ''
|
||||
|
||||
return nextLang
|
||||
? `/${segments.join('/')}`
|
||||
: `/${segments.slice(1).join('/')}`
|
||||
// 检查第一段是否是语言代码(不包括默认语言)
|
||||
const isFirstSegmentLang = availableLangs.includes(firstSegment) && firstSegment !== defaultLocale
|
||||
|
||||
// 处理不同的情况
|
||||
if (nextLang === defaultLocale) {
|
||||
// 如果下一个语言是默认语言,则移除语言段
|
||||
if (isFirstSegmentLang) {
|
||||
newSegments.shift()
|
||||
}
|
||||
}
|
||||
else {
|
||||
// 如果下一个语言不是默认语言
|
||||
if (isFirstSegmentLang) {
|
||||
// 如果第一段是语言代码,则替换它
|
||||
newSegments[0] = nextLang
|
||||
}
|
||||
else {
|
||||
// 如果第一段不是语言代码,则添加新的语言代码
|
||||
newSegments.unshift(nextLang)
|
||||
}
|
||||
}
|
||||
|
||||
return nextLang
|
||||
? `/${nextLang}${pathname}`
|
||||
: pathname
|
||||
// 返回新路径
|
||||
// 处理空路径的特殊情况,避免生成 // 这样的路径
|
||||
if (newSegments.length === 0) {
|
||||
return '/'
|
||||
}
|
||||
return `/${newSegments.join('/')}/`
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -14,9 +14,9 @@ const postsCollection = defineCollection({
|
|||
toc: z.boolean().optional().default(false),
|
||||
draft: z.boolean().optional().default(false),
|
||||
lang: z.string().optional().default(''),
|
||||
slug: z.string().optional().default('').refine(
|
||||
slug => !slug || /^[\w\-]*$/.test(slug),
|
||||
{ message: 'Slug can only contain letters, numbers, hyphens and underscores' },
|
||||
abbrlink: z.string().optional().default('').refine(
|
||||
abbrlink => !abbrlink || /^[a-z0-9\-]*$/.test(abbrlink),
|
||||
{ message: 'Abbrlink can only contain letters, numbers, hyphens and underscores' },
|
||||
),
|
||||
minutes: z.number().optional(),
|
||||
}),
|
||||
|
|
190
src/content/posts/故乡/故乡 copy 2.mdx
Normal file
190
src/content/posts/故乡/故乡 copy 2.mdx
Normal file
|
@ -0,0 +1,190 @@
|
|||
---
|
||||
title: 故鄉
|
||||
published: 1921-01-10
|
||||
tags: ["鲁迅","经典读本"]
|
||||
lang: ja
|
||||
abbrlink: hometown
|
||||
---
|
||||
import { Image } from 'astro:assets';
|
||||
|
||||
lang: ja
|
||||
|
||||
<Image src="https://image.radishzz.cc/picsmaller/03.webp" inferSize alt="这是图片的说明文字" />
|
||||
|
||||
我冒了嚴寒,回到相隔二千餘里,別了二十餘年的故鄉去。
|
||||
|
||||
時候既然是深冬;漸近故鄉時,天氣又陰晦了,冷風吹進船艙中,嗚嗚的響,從蓬隙向外一望,蒼黃的天底下,遠近橫著幾個蕭索的荒村,沒有一些活氣。我的心禁不住悲涼起來了。
|
||||
|
||||
阿!這不是我二十年來時時記得的故鄉?
|
||||
|
||||
我所記得的故鄉全不如此。我的故鄉好得多了。但要我記起他的美麗,說出他的佳處來,卻又沒有影像,沒有言辭了。仿佛也就如此。於是我自己解釋說:故鄉本也如此,——雖然沒有進步,也未必有如我所感的悲涼,這只是我自己心情的改變罷了,因為我這次回鄉,本沒有什麼好心緒。
|
||||
|
||||
我這次是專為了別他而來的。我們多年聚族而居的老屋,已經公同賣給別姓了,交屋的期限,只在本年,所以必須趕在正月初一以前,永別了熟識的老屋,而且遠離了熟識的故鄉,搬家到我在謀食的異地去。
|
||||
|
||||
第二日清早晨我到了我家的門口了。瓦楞上許多枯草的斷莖當風抖著,正在說明這老屋難免易主的原因。幾房的本家大約已經搬走了,所以很寂靜。我到了自家的房外,我的母親早已迎著出來了,接著便飛出了八歲的侄兒宏兒。 -->
|
||||
|
||||
我的母親很高興,但也藏著許多淒涼的神情,教我坐下,歇息,喝茶,且不談搬家的事。宏兒沒有見過我,遠遠的對面站著只是看。
|
||||
|
||||
但我們終於談到搬家的事。我說外間的寓所已經租定了,又買了幾件傢具,此外須將家裡所有的木器賣去,再去增添。母親也說好,而且行李也略已齊集,木器不便搬運的,也小半賣去了,只是收不起錢來。
|
||||
|
||||
「你休息一兩天,去拜望親戚本家一回,我們便可以走了。」母親說。
|
||||
|
||||
「是的。」
|
||||
|
||||
「還有閏土,他每到我家來時,總問起你,很想見你一回面。我已經將你到家的大約日期通知他,他也許就要來了。」
|
||||
|
||||
這時候,我的腦裡忽然閃出一幅神異的圖畫來:深藍的天空中掛著一輪金黃的圓月,下面是海邊的沙地,都種著一望無際的碧綠的西瓜,其間有一個十一二歲的少年,項帶銀圈,手捏一柄鋼叉,向一匹猹盡力的刺去,那猹卻將身一扭,反從他的胯下逃走了。
|
||||
|
||||
這少年便是閏土。我認識他時,也不過十多歲,離現在將有三十年了;那時我的父親還在世,家景也好,我正是一個少爺。那一年,我家是一件大祭祀的值年。這祭祀,說是三十多年才能輪到一回,所以很鄭重;正月裡供祖像,供品很多,祭器很講究,拜的人也很多,祭器也很要防偷去。我家只有一個忙月(我們這裡給人做工的分三種:整年給一定人家做工的叫長工;按日給人做工的叫短工;自己也種地,只在過年過節以及收租時候來給一定人家做工的稱忙月),忙不過來,他便對父親說,可以叫他的兒子閏土來管祭器的。
|
||||
|
||||
我的父親允許了;我也很高興,因為我早聽到閏土這名字,而且知道他和我仿佛年紀,閏月生的,五行缺土,所以他的父親叫他閏土。他是能裝弶捉小鳥雀的。
|
||||
|
||||
我於是日日盼望新年,新年到,閏土也就到了。好容易到了年末,有一日,母親告訴我,閏土來了,我便飛跑的去看。他正在廚房裡,紫色的圓臉,頭戴一頂小氈帽,頸上套一個明晃晃的銀項圈,這可見他的父親十分愛他,怕他死去,所以在神佛面前許下願心,用圈子將他套住了。他見人很怕羞,只是不怕我,沒有旁人的時候,便和我說話,於是不到半日,我們便熟識了。
|
||||
|
||||
我們那時候不知道談些什麼,只記得閏土很高興,說是上城之後,見了許多沒有見過的東西。
|
||||
|
||||
第二日,我便要他捕鳥。他說:
|
||||
|
||||
“這不能。須大雪下了才好。我們沙地上,下了雪,我掃出一塊空地來,用短棒支起一個大竹匾,撒下秕穀,看鳥雀來吃時,我遠遠地將縛在棒上的繩子只一拉,那鳥雀就罩在竹匾下了。什麼都有:稻雞,角雞,鵓鴣,藍背……”
|
||||
|
||||
我於是又很盼望下雪。
|
||||
|
||||
閏土又對我說:
|
||||
|
||||
“現在太冷,你夏天到我們這裡來。我們日裡到海邊撿貝殼去,紅的綠的都有,鬼見怕也有,觀音手也有。晚上我和爹管西瓜去,你也去。”
|
||||
|
||||
“管賊麽?”
|
||||
|
||||
“不是。走路的人口渴了摘一個瓜吃,我們這裡是不算偷的。要管的是獾豬,刺蝟,猹。月亮底下,你聽,啦啦的響了,猹在咬瓜了。你便捏了胡叉,輕輕地走去……”
|
||||
|
||||
我那時並不知道這所謂猹的是怎麼一件東西——便是現在也沒有知道——只是無端的覺得狀如小狗而很兇猛。
|
||||
|
||||
“他不咬人麽?”
|
||||
|
||||
“有胡叉呢。走到了,看見猹了,你便刺。這畜生很伶俐,倒向你奔來,反從胯下竄了。他的皮毛是油一般的滑……”
|
||||
|
||||
我素不知道天下有這許多新鮮事:海邊有如許五色的貝殼;西瓜有這樣危險的經歷,我先前單知道他在水果店裡出賣罷了。
|
||||
|
||||
“我們沙地裡,潮汛要來的時候,就有許多跳魚兒只是跳,都有青蛙似的兩個腳……”
|
||||
|
||||
阿!閏土的心裡有無窮無盡的希奇的事,都是我往常的朋友所不知道的。他們不知道一些事,閏土在海邊時,他們都和我一樣只看見院子裡高牆上的四角的天空。
|
||||
|
||||
可惜正月過去了,閏土須回家裡去,我急得大哭,他也躲到廚房裡,哭著不肯出門,但終於被他父親帶走了。他後來還托他的父親帶給我一包貝殼和幾支很好看的鳥毛,我也曾送他一兩次東西,但從此沒有再見面。
|
||||
|
||||
現在我的母親提起了他,我這兒時的記憶,忽而全都閃電似的蘇生過來,似乎看到了我的美麗的故鄉了。我應聲說:
|
||||
|
||||
“這好極!他,——怎樣?……”
|
||||
|
||||
“他?……他景況也很不如意……”母親說著,便向房外看,“這些人又來了。說是買木器,順手也就隨便拿走的,我得去看看。”
|
||||
|
||||
母親站起身,出去了。門外有幾個女人的聲音。我便招宏兒走近面前,和他閑話:問他可會寫字,可願意出門。
|
||||
|
||||
“我們坐火車去麽?”
|
||||
|
||||
“我們坐火車去。”
|
||||
|
||||
“船呢?”
|
||||
|
||||
“先坐船,……”
|
||||
|
||||
“哈!這模樣了!鬍子這麼長了!”一種尖利的怪聲突然大叫起來。
|
||||
|
||||
我吃了一嚇,趕忙抬起頭,卻見一個凸顴骨、薄嘴唇、五十歲上下的女人站在我面前,兩手搭在髀間,沒有繫裙,張著兩腳,正像一個畫圖儀器裡細腳伶仃的圓規。
|
||||
|
||||
我愕然了。
|
||||
|
||||
“不認識了麽?我還抱過你咧!”
|
||||
|
||||
我愈加愕然了。幸而我的母親也就進來,從旁說:
|
||||
|
||||
“他多年出門,統忘卻了。你該記得罷,”便向著我說,“這是斜對門的楊二嫂,……開豆腐店的。”
|
||||
|
||||
哦,我記得了。我孩子時候,在斜對門的豆腐店裡確乎終日坐著一個楊二嫂,人都叫伊“豆腐西施”。但是擦著白粉,顴骨沒有這麼高,嘴唇也沒有這麼薄,而且終日坐著,我也從沒有見過這圓規式的姿勢。那時人說:因為伊,這豆腐店的買賣非常好。但這大約因為年齡的關係,我卻並未蒙著一毫感化,所以竟完全忘卻了。然而圓規很不平,顯出鄙夷的神色,仿佛嗤笑法國人不知道拿破侖,美國人不知道華盛頓似的,冷笑說:
|
||||
|
||||
“忘了?這真是貴人眼高……”
|
||||
|
||||
“那有這事……我……”我惶恐著,站起來說。
|
||||
|
||||
“那麼,我對你說。迅哥兒,你闊了,搬動又笨重,你還要什麼這些破爛木器,讓我拿去罷。我們小戶人家,用得著。”
|
||||
|
||||
“我並沒有闊哩。我須賣了這些,再去……”
|
||||
|
||||
“阿呀呀,你放了道台了,還說不闊?你現在有三房姨太太;出門便是八抬的大轎,還說不闊?嚇,什麼都瞞不過我。”
|
||||
|
||||
我知道無話可說了,便閉了口,默默的站著。
|
||||
|
||||
“阿呀阿呀,真是愈有錢,便愈是一毫不肯放鬆,愈是一毫不肯放鬆,便愈有錢……”圓規一面憤憤的迴轉身,一面絮絮的說,慢慢向外走,順便將我母親的一副手套塞在褲腰裡,出去了。
|
||||
|
||||
此後又有近處的本家和親戚來訪問我。我一面應酬,偷空便收拾些行李,這樣的過了三四天。
|
||||
|
||||
一日是天氣很冷的午後,我吃過午飯,坐著喝茶,覺得外面有人進來了,便回頭去看。我看時,不由的非常出驚,慌忙站起身,迎著走去。
|
||||
|
||||
這來的便是閏土。雖然我一見便知道是閏土,但又不是我這記憶上的閏土了。他身材增加了一倍;先前的紫色的圓臉,已經變作灰黃,而且加上了很深的皺紋;眼睛也像他父親一樣,周圍都腫得通紅,這我知道,在海邊種地的人,終日吹著海風,大抵是這樣的。他頭上是一頂破氈帽,身上只一件極薄的棉衣,渾身瑟索著;手裡提著一個紙包和一支長煙管,那手也不是我所記得的紅活圓實的手,卻又粗又笨而且開裂,像是松樹皮了。
|
||||
|
||||
我這時很興奮,但不知道怎麼說才好,只是說:
|
||||
|
||||
“阿!閏土哥,——你來了?……”
|
||||
|
||||
我接著便有許多話,想要連珠一般湧出:角雞,跳魚兒,貝殼,猹,……但又總覺得被什麼擋著似的,單在腦裡面迴旋,吐不出口外去。
|
||||
|
||||
他站住了,臉上現出歡喜和淒涼的神情;動著嘴唇,卻沒有作聲。他的態度終於恭敬起來了,分明的叫道:
|
||||
|
||||
“老爺!……”
|
||||
|
||||
我似乎打了一個寒噤;我就知道,我們之間已經隔了一層可悲的厚障壁了。我也說不出話。
|
||||
|
||||
他回過頭去說,“水生,給老爺磕頭。”便拖出躲在背後的孩子來,這正是一個廿年前的閏土,只是黃瘦些,頸子上沒有銀圈罷了。“這是第五個孩子,沒有見過世面,躲躲閃閃……”
|
||||
|
||||
母親和宏兒下樓來了,他們大約也聽到了聲音。
|
||||
|
||||
“老太太。信是早收到了。我實在喜歡的不得了,知道老爺回來……”閏土說。
|
||||
|
||||
“阿,你怎的這樣客氣起來。你們先前不是哥弟稱呼麽?還是照舊:迅哥兒。”母親高興的說。
|
||||
|
||||
“阿呀,老太太真是……這成什麼規矩。那時是孩子,不懂事……”閏土說著,又叫水生上來打拱,那孩子卻害羞,緊緊的只貼在他背後。
|
||||
|
||||
“他就是水生?第五個?都是生人,怕生也難怪的;還是宏兒和他去走走。”母親說。
|
||||
|
||||
宏兒聽得這話,便來招水生,水生卻鬆鬆爽爽同他一路出去了。母親叫閏土坐,他遲疑了一回,終於就了坐,將長煙管靠在桌旁,遞過紙包來,說:
|
||||
|
||||
“冬天沒有什麼東西了。這一點乾青豆倒是自家曬在那裡的,請老爺……”
|
||||
|
||||
我問問他的景況。他只是搖頭。
|
||||
|
||||
“非常難。第六個孩子也會幫忙了,卻總是吃不夠……又不太平……什麼地方都要錢,沒有規定……收成又壞。種出東西來,挑去賣,總要捐幾回錢,折了本;不去賣,又只能爛掉……”
|
||||
|
||||
他只是搖頭;臉上雖然刻著許多皺紋,卻全然不動,仿佛石像一般。他大約只是覺得苦,卻又形容不出,沉默了片時,便拿起煙管來默默的吸煙了。
|
||||
|
||||
母親問他,知道他的家裡事務忙,明天便得回去;又沒有吃過午飯,便叫他自己到廚下炒飯吃去。
|
||||
|
||||
他出去了;母親和我都嘆息他的景況:多子,饑荒,苛稅,兵,匪,官,紳,都苦得他像一個木偶人了。母親對我說,凡是不必搬走的東西,盡可以送他,可以聽他自己去揀擇。
|
||||
|
||||
下午,他揀好了幾件東西:兩條長桌,四個椅子,一副香爐和燭臺,一桿抬秤。他又要所有的草灰(我們這裡煮飯是燒稻草的,那灰,可以做沙地的肥料),待我們啟程的時候,他用船來載去。
|
||||
|
||||
夜間,我們又談些閑天,都是無關緊要的話;第二天早晨,他就領了水生回去了。
|
||||
|
||||
又過了九日,是我們啟程的日期。閏土早晨便到了,水生沒有同來,卻只帶著一個五歲的女兒管船隻。我們終日很忙碌,再沒有談天的工夫。來客也不少,有送行的,有拿東西的,有送行兼拿東西的。待到傍晚我們上船的時候,這老屋裡的所有破舊大小粗細東西,已經一掃而空了。
|
||||
|
||||
我們的船向前走,兩岸的青山在黃昏中,都裝成了深黛顏色,連著退向船後梢去。
|
||||
|
||||
宏兒和我靠著船窗,同看外面模糊的風景,他忽然問道:
|
||||
|
||||
“大伯!我們什麼時候回來?”
|
||||
|
||||
“回來?你怎麼還沒有走就想回來了。”
|
||||
|
||||
“可是,水生約我到他家玩去咧……”他睜著大的黑眼睛,癡癡的想。
|
||||
|
||||
我和母親也都有些惘然,於是又提起閏土來。母親說,那豆腐西施的楊二嫂,自從我家收拾行李以來,本是每日必到的,前天伊在灰堆裡,掏出十多個碗碟來,議論之後,便定說是閏土埋著的,他可以在運灰的時候,一齊搬回家裡去;楊二嫂發見了這件事,自己很以為功,便拿了那狗氣殺(這是我們這裡養雞的器具,木盤上面有著柵欄,內盛食料,雞可以伸進頸子去啄,狗卻不能,只能看著氣死),飛也似的跑了,虧伊裝著這麼高低的小腳,竟跑得這樣快。
|
||||
|
||||
老屋離我愈遠了;故鄉的山水也都漸漸遠離了我,但我卻並不感到怎樣的留戀。我只覺得我四面有看不見的高牆,將我隔成孤身,使我非常氣悶;那西瓜地上的銀項圈的小英雄的影像,我本來十分清楚,現在卻忽地模糊了,又使我非常的悲哀。
|
||||
|
||||
母親和宏兒都睡著了。
|
||||
|
||||
我躺著,聽船底潺潺的水聲,知道我在走我的路。我想:我竟與閏土隔絕到這地步了,但我們的後輩還是一氣,宏兒不是正在想念水生麽。我希望他們不再像我,又大家隔膜起來……然而我又不願意他們因為要一氣,都如我的辛苦展轉而生活,也不願意他們都如閏土的辛苦麻木而生活,也不願意都如別人的辛苦恣睢而生活。他們應該有新的生活,為我們所未經生活過的。
|
||||
|
||||
我想到希望,忽然害怕起來了。閏土要香爐和燭臺的時候,我還暗地裡笑他,以為他總是崇拜偶像,什麼時候都不忘卻。現在我所謂希望,不也是我自己手製的偶像麽?只是他的願望切近,我的願望茫遠罷了。
|
||||
|
||||
我在朦朧中,眼前展開一片海邊碧綠的沙地來,上面深藍的天空中掛著一輪金黃的圓月。我想:希望本是無所謂有,無所謂無的。這正如地上的路;其實地上本沒有路,走的人多了,也便成了路。
|
||||
|
||||
一九二一年一月
|
190
src/content/posts/故乡/故乡 copy 3.mdx
Normal file
190
src/content/posts/故乡/故乡 copy 3.mdx
Normal file
|
@ -0,0 +1,190 @@
|
|||
---
|
||||
title: 故鄉
|
||||
published: 1921-01-10
|
||||
tags: ["鲁迅","经典读本"]
|
||||
lang: en
|
||||
abbrlink: hometown
|
||||
---
|
||||
import { Image } from 'astro:assets';
|
||||
|
||||
lang: en
|
||||
|
||||
<Image src="https://image.radishzz.cc/picsmaller/03.webp" inferSize alt="这是图片的说明文字" />
|
||||
|
||||
我冒了嚴寒,回到相隔二千餘里,別了二十餘年的故鄉去。
|
||||
|
||||
時候既然是深冬;漸近故鄉時,天氣又陰晦了,冷風吹進船艙中,嗚嗚的響,從蓬隙向外一望,蒼黃的天底下,遠近橫著幾個蕭索的荒村,沒有一些活氣。我的心禁不住悲涼起來了。
|
||||
|
||||
阿!這不是我二十年來時時記得的故鄉?
|
||||
|
||||
我所記得的故鄉全不如此。我的故鄉好得多了。但要我記起他的美麗,說出他的佳處來,卻又沒有影像,沒有言辭了。仿佛也就如此。於是我自己解釋說:故鄉本也如此,——雖然沒有進步,也未必有如我所感的悲涼,這只是我自己心情的改變罷了,因為我這次回鄉,本沒有什麼好心緒。
|
||||
|
||||
我這次是專為了別他而來的。我們多年聚族而居的老屋,已經公同賣給別姓了,交屋的期限,只在本年,所以必須趕在正月初一以前,永別了熟識的老屋,而且遠離了熟識的故鄉,搬家到我在謀食的異地去。
|
||||
|
||||
第二日清早晨我到了我家的門口了。瓦楞上許多枯草的斷莖當風抖著,正在說明這老屋難免易主的原因。幾房的本家大約已經搬走了,所以很寂靜。我到了自家的房外,我的母親早已迎著出來了,接著便飛出了八歲的侄兒宏兒。 -->
|
||||
|
||||
我的母親很高興,但也藏著許多淒涼的神情,教我坐下,歇息,喝茶,且不談搬家的事。宏兒沒有見過我,遠遠的對面站著只是看。
|
||||
|
||||
但我們終於談到搬家的事。我說外間的寓所已經租定了,又買了幾件傢具,此外須將家裡所有的木器賣去,再去增添。母親也說好,而且行李也略已齊集,木器不便搬運的,也小半賣去了,只是收不起錢來。
|
||||
|
||||
「你休息一兩天,去拜望親戚本家一回,我們便可以走了。」母親說。
|
||||
|
||||
「是的。」
|
||||
|
||||
「還有閏土,他每到我家來時,總問起你,很想見你一回面。我已經將你到家的大約日期通知他,他也許就要來了。」
|
||||
|
||||
這時候,我的腦裡忽然閃出一幅神異的圖畫來:深藍的天空中掛著一輪金黃的圓月,下面是海邊的沙地,都種著一望無際的碧綠的西瓜,其間有一個十一二歲的少年,項帶銀圈,手捏一柄鋼叉,向一匹猹盡力的刺去,那猹卻將身一扭,反從他的胯下逃走了。
|
||||
|
||||
這少年便是閏土。我認識他時,也不過十多歲,離現在將有三十年了;那時我的父親還在世,家景也好,我正是一個少爺。那一年,我家是一件大祭祀的值年。這祭祀,說是三十多年才能輪到一回,所以很鄭重;正月裡供祖像,供品很多,祭器很講究,拜的人也很多,祭器也很要防偷去。我家只有一個忙月(我們這裡給人做工的分三種:整年給一定人家做工的叫長工;按日給人做工的叫短工;自己也種地,只在過年過節以及收租時候來給一定人家做工的稱忙月),忙不過來,他便對父親說,可以叫他的兒子閏土來管祭器的。
|
||||
|
||||
我的父親允許了;我也很高興,因為我早聽到閏土這名字,而且知道他和我仿佛年紀,閏月生的,五行缺土,所以他的父親叫他閏土。他是能裝弶捉小鳥雀的。
|
||||
|
||||
我於是日日盼望新年,新年到,閏土也就到了。好容易到了年末,有一日,母親告訴我,閏土來了,我便飛跑的去看。他正在廚房裡,紫色的圓臉,頭戴一頂小氈帽,頸上套一個明晃晃的銀項圈,這可見他的父親十分愛他,怕他死去,所以在神佛面前許下願心,用圈子將他套住了。他見人很怕羞,只是不怕我,沒有旁人的時候,便和我說話,於是不到半日,我們便熟識了。
|
||||
|
||||
我們那時候不知道談些什麼,只記得閏土很高興,說是上城之後,見了許多沒有見過的東西。
|
||||
|
||||
第二日,我便要他捕鳥。他說:
|
||||
|
||||
“這不能。須大雪下了才好。我們沙地上,下了雪,我掃出一塊空地來,用短棒支起一個大竹匾,撒下秕穀,看鳥雀來吃時,我遠遠地將縛在棒上的繩子只一拉,那鳥雀就罩在竹匾下了。什麼都有:稻雞,角雞,鵓鴣,藍背……”
|
||||
|
||||
我於是又很盼望下雪。
|
||||
|
||||
閏土又對我說:
|
||||
|
||||
“現在太冷,你夏天到我們這裡來。我們日裡到海邊撿貝殼去,紅的綠的都有,鬼見怕也有,觀音手也有。晚上我和爹管西瓜去,你也去。”
|
||||
|
||||
“管賊麽?”
|
||||
|
||||
“不是。走路的人口渴了摘一個瓜吃,我們這裡是不算偷的。要管的是獾豬,刺蝟,猹。月亮底下,你聽,啦啦的響了,猹在咬瓜了。你便捏了胡叉,輕輕地走去……”
|
||||
|
||||
我那時並不知道這所謂猹的是怎麼一件東西——便是現在也沒有知道——只是無端的覺得狀如小狗而很兇猛。
|
||||
|
||||
“他不咬人麽?”
|
||||
|
||||
“有胡叉呢。走到了,看見猹了,你便刺。這畜生很伶俐,倒向你奔來,反從胯下竄了。他的皮毛是油一般的滑……”
|
||||
|
||||
我素不知道天下有這許多新鮮事:海邊有如許五色的貝殼;西瓜有這樣危險的經歷,我先前單知道他在水果店裡出賣罷了。
|
||||
|
||||
“我們沙地裡,潮汛要來的時候,就有許多跳魚兒只是跳,都有青蛙似的兩個腳……”
|
||||
|
||||
阿!閏土的心裡有無窮無盡的希奇的事,都是我往常的朋友所不知道的。他們不知道一些事,閏土在海邊時,他們都和我一樣只看見院子裡高牆上的四角的天空。
|
||||
|
||||
可惜正月過去了,閏土須回家裡去,我急得大哭,他也躲到廚房裡,哭著不肯出門,但終於被他父親帶走了。他後來還托他的父親帶給我一包貝殼和幾支很好看的鳥毛,我也曾送他一兩次東西,但從此沒有再見面。
|
||||
|
||||
現在我的母親提起了他,我這兒時的記憶,忽而全都閃電似的蘇生過來,似乎看到了我的美麗的故鄉了。我應聲說:
|
||||
|
||||
“這好極!他,——怎樣?……”
|
||||
|
||||
“他?……他景況也很不如意……”母親說著,便向房外看,“這些人又來了。說是買木器,順手也就隨便拿走的,我得去看看。”
|
||||
|
||||
母親站起身,出去了。門外有幾個女人的聲音。我便招宏兒走近面前,和他閑話:問他可會寫字,可願意出門。
|
||||
|
||||
“我們坐火車去麽?”
|
||||
|
||||
“我們坐火車去。”
|
||||
|
||||
“船呢?”
|
||||
|
||||
“先坐船,……”
|
||||
|
||||
“哈!這模樣了!鬍子這麼長了!”一種尖利的怪聲突然大叫起來。
|
||||
|
||||
我吃了一嚇,趕忙抬起頭,卻見一個凸顴骨、薄嘴唇、五十歲上下的女人站在我面前,兩手搭在髀間,沒有繫裙,張著兩腳,正像一個畫圖儀器裡細腳伶仃的圓規。
|
||||
|
||||
我愕然了。
|
||||
|
||||
“不認識了麽?我還抱過你咧!”
|
||||
|
||||
我愈加愕然了。幸而我的母親也就進來,從旁說:
|
||||
|
||||
“他多年出門,統忘卻了。你該記得罷,”便向著我說,“這是斜對門的楊二嫂,……開豆腐店的。”
|
||||
|
||||
哦,我記得了。我孩子時候,在斜對門的豆腐店裡確乎終日坐著一個楊二嫂,人都叫伊“豆腐西施”。但是擦著白粉,顴骨沒有這麼高,嘴唇也沒有這麼薄,而且終日坐著,我也從沒有見過這圓規式的姿勢。那時人說:因為伊,這豆腐店的買賣非常好。但這大約因為年齡的關係,我卻並未蒙著一毫感化,所以竟完全忘卻了。然而圓規很不平,顯出鄙夷的神色,仿佛嗤笑法國人不知道拿破侖,美國人不知道華盛頓似的,冷笑說:
|
||||
|
||||
“忘了?這真是貴人眼高……”
|
||||
|
||||
“那有這事……我……”我惶恐著,站起來說。
|
||||
|
||||
“那麼,我對你說。迅哥兒,你闊了,搬動又笨重,你還要什麼這些破爛木器,讓我拿去罷。我們小戶人家,用得著。”
|
||||
|
||||
“我並沒有闊哩。我須賣了這些,再去……”
|
||||
|
||||
“阿呀呀,你放了道台了,還說不闊?你現在有三房姨太太;出門便是八抬的大轎,還說不闊?嚇,什麼都瞞不過我。”
|
||||
|
||||
我知道無話可說了,便閉了口,默默的站著。
|
||||
|
||||
“阿呀阿呀,真是愈有錢,便愈是一毫不肯放鬆,愈是一毫不肯放鬆,便愈有錢……”圓規一面憤憤的迴轉身,一面絮絮的說,慢慢向外走,順便將我母親的一副手套塞在褲腰裡,出去了。
|
||||
|
||||
此後又有近處的本家和親戚來訪問我。我一面應酬,偷空便收拾些行李,這樣的過了三四天。
|
||||
|
||||
一日是天氣很冷的午後,我吃過午飯,坐著喝茶,覺得外面有人進來了,便回頭去看。我看時,不由的非常出驚,慌忙站起身,迎著走去。
|
||||
|
||||
這來的便是閏土。雖然我一見便知道是閏土,但又不是我這記憶上的閏土了。他身材增加了一倍;先前的紫色的圓臉,已經變作灰黃,而且加上了很深的皺紋;眼睛也像他父親一樣,周圍都腫得通紅,這我知道,在海邊種地的人,終日吹著海風,大抵是這樣的。他頭上是一頂破氈帽,身上只一件極薄的棉衣,渾身瑟索著;手裡提著一個紙包和一支長煙管,那手也不是我所記得的紅活圓實的手,卻又粗又笨而且開裂,像是松樹皮了。
|
||||
|
||||
我這時很興奮,但不知道怎麼說才好,只是說:
|
||||
|
||||
“阿!閏土哥,——你來了?……”
|
||||
|
||||
我接著便有許多話,想要連珠一般湧出:角雞,跳魚兒,貝殼,猹,……但又總覺得被什麼擋著似的,單在腦裡面迴旋,吐不出口外去。
|
||||
|
||||
他站住了,臉上現出歡喜和淒涼的神情;動著嘴唇,卻沒有作聲。他的態度終於恭敬起來了,分明的叫道:
|
||||
|
||||
“老爺!……”
|
||||
|
||||
我似乎打了一個寒噤;我就知道,我們之間已經隔了一層可悲的厚障壁了。我也說不出話。
|
||||
|
||||
他回過頭去說,“水生,給老爺磕頭。”便拖出躲在背後的孩子來,這正是一個廿年前的閏土,只是黃瘦些,頸子上沒有銀圈罷了。“這是第五個孩子,沒有見過世面,躲躲閃閃……”
|
||||
|
||||
母親和宏兒下樓來了,他們大約也聽到了聲音。
|
||||
|
||||
“老太太。信是早收到了。我實在喜歡的不得了,知道老爺回來……”閏土說。
|
||||
|
||||
“阿,你怎的這樣客氣起來。你們先前不是哥弟稱呼麽?還是照舊:迅哥兒。”母親高興的說。
|
||||
|
||||
“阿呀,老太太真是……這成什麼規矩。那時是孩子,不懂事……”閏土說著,又叫水生上來打拱,那孩子卻害羞,緊緊的只貼在他背後。
|
||||
|
||||
“他就是水生?第五個?都是生人,怕生也難怪的;還是宏兒和他去走走。”母親說。
|
||||
|
||||
宏兒聽得這話,便來招水生,水生卻鬆鬆爽爽同他一路出去了。母親叫閏土坐,他遲疑了一回,終於就了坐,將長煙管靠在桌旁,遞過紙包來,說:
|
||||
|
||||
“冬天沒有什麼東西了。這一點乾青豆倒是自家曬在那裡的,請老爺……”
|
||||
|
||||
我問問他的景況。他只是搖頭。
|
||||
|
||||
“非常難。第六個孩子也會幫忙了,卻總是吃不夠……又不太平……什麼地方都要錢,沒有規定……收成又壞。種出東西來,挑去賣,總要捐幾回錢,折了本;不去賣,又只能爛掉……”
|
||||
|
||||
他只是搖頭;臉上雖然刻著許多皺紋,卻全然不動,仿佛石像一般。他大約只是覺得苦,卻又形容不出,沉默了片時,便拿起煙管來默默的吸煙了。
|
||||
|
||||
母親問他,知道他的家裡事務忙,明天便得回去;又沒有吃過午飯,便叫他自己到廚下炒飯吃去。
|
||||
|
||||
他出去了;母親和我都嘆息他的景況:多子,饑荒,苛稅,兵,匪,官,紳,都苦得他像一個木偶人了。母親對我說,凡是不必搬走的東西,盡可以送他,可以聽他自己去揀擇。
|
||||
|
||||
下午,他揀好了幾件東西:兩條長桌,四個椅子,一副香爐和燭臺,一桿抬秤。他又要所有的草灰(我們這裡煮飯是燒稻草的,那灰,可以做沙地的肥料),待我們啟程的時候,他用船來載去。
|
||||
|
||||
夜間,我們又談些閑天,都是無關緊要的話;第二天早晨,他就領了水生回去了。
|
||||
|
||||
又過了九日,是我們啟程的日期。閏土早晨便到了,水生沒有同來,卻只帶著一個五歲的女兒管船隻。我們終日很忙碌,再沒有談天的工夫。來客也不少,有送行的,有拿東西的,有送行兼拿東西的。待到傍晚我們上船的時候,這老屋裡的所有破舊大小粗細東西,已經一掃而空了。
|
||||
|
||||
我們的船向前走,兩岸的青山在黃昏中,都裝成了深黛顏色,連著退向船後梢去。
|
||||
|
||||
宏兒和我靠著船窗,同看外面模糊的風景,他忽然問道:
|
||||
|
||||
“大伯!我們什麼時候回來?”
|
||||
|
||||
“回來?你怎麼還沒有走就想回來了。”
|
||||
|
||||
“可是,水生約我到他家玩去咧……”他睜著大的黑眼睛,癡癡的想。
|
||||
|
||||
我和母親也都有些惘然,於是又提起閏土來。母親說,那豆腐西施的楊二嫂,自從我家收拾行李以來,本是每日必到的,前天伊在灰堆裡,掏出十多個碗碟來,議論之後,便定說是閏土埋著的,他可以在運灰的時候,一齊搬回家裡去;楊二嫂發見了這件事,自己很以為功,便拿了那狗氣殺(這是我們這裡養雞的器具,木盤上面有著柵欄,內盛食料,雞可以伸進頸子去啄,狗卻不能,只能看著氣死),飛也似的跑了,虧伊裝著這麼高低的小腳,竟跑得這樣快。
|
||||
|
||||
老屋離我愈遠了;故鄉的山水也都漸漸遠離了我,但我卻並不感到怎樣的留戀。我只覺得我四面有看不見的高牆,將我隔成孤身,使我非常氣悶;那西瓜地上的銀項圈的小英雄的影像,我本來十分清楚,現在卻忽地模糊了,又使我非常的悲哀。
|
||||
|
||||
母親和宏兒都睡著了。
|
||||
|
||||
我躺著,聽船底潺潺的水聲,知道我在走我的路。我想:我竟與閏土隔絕到這地步了,但我們的後輩還是一氣,宏兒不是正在想念水生麽。我希望他們不再像我,又大家隔膜起來……然而我又不願意他們因為要一氣,都如我的辛苦展轉而生活,也不願意他們都如閏土的辛苦麻木而生活,也不願意都如別人的辛苦恣睢而生活。他們應該有新的生活,為我們所未經生活過的。
|
||||
|
||||
我想到希望,忽然害怕起來了。閏土要香爐和燭臺的時候,我還暗地裡笑他,以為他總是崇拜偶像,什麼時候都不忘卻。現在我所謂希望,不也是我自己手製的偶像麽?只是他的願望切近,我的願望茫遠罷了。
|
||||
|
||||
我在朦朧中,眼前展開一片海邊碧綠的沙地來,上面深藍的天空中掛著一輪金黃的圓月。我想:希望本是無所謂有,無所謂無的。這正如地上的路;其實地上本沒有路,走的人多了,也便成了路。
|
||||
|
||||
一九二一年一月
|
|
@ -2,9 +2,13 @@
|
|||
title: 故鄉
|
||||
published: 1921-01-10
|
||||
tags: ["鲁迅","经典读本"]
|
||||
lang: zh
|
||||
abbrlink: hometown
|
||||
---
|
||||
import { Image } from 'astro:assets';
|
||||
|
||||
lang: zh 我冒了嚴寒,回到相隔二千餘里,別了二十餘年的故鄉去。
|
||||
|
||||
<Image src="https://image.radishzz.cc/picsmaller/03.webp" inferSize alt="这是图片的说明文字" />
|
||||
|
||||
我冒了嚴寒,回到相隔二千餘里,別了二十餘年的故鄉去。
|
|
@ -46,7 +46,7 @@ const { commentURL = '', imageHostURL = '', customGoogleAnalyticsJS = '', custom
|
|||
{[locale, ...moreLocale].map(lang => (
|
||||
<link
|
||||
rel="alternate"
|
||||
href={`${url}${lang === locale ? '' : `/${lang}`}`}
|
||||
href={`${url}${lang === locale ? '' : `/${lang}/`}`}
|
||||
hreflang={lang === 'zh-tw' ? 'zh-TW' : lang}
|
||||
/>
|
||||
))}
|
||||
|
|
|
@ -21,7 +21,7 @@ const postsByYear = await getPostsByYear(lang)
|
|||
<ul>
|
||||
{pinnedPosts.map(post => (
|
||||
<li>
|
||||
<a href={`/${lang}/posts/${post.data.slug || post.slug}/`}>
|
||||
<a href={`/${lang}/posts/${post.data.abbrlink || post.slug}/`}>
|
||||
{post.data.title}
|
||||
<time class="block lg:inline lg:before:content-['_']">
|
||||
{post.data.published.toLocaleDateString('en-US', { month: '2-digit', day: '2-digit' }).replace('/', '-')}
|
||||
|
@ -45,7 +45,7 @@ const postsByYear = await getPostsByYear(lang)
|
|||
// Single Post
|
||||
<li class="mt-6">
|
||||
{/* Post Title */}
|
||||
<a href={`/${lang}/posts/${post.data.slug || post.slug}`}>{post.data.title}</a>
|
||||
<a href={`/${lang}/posts/${post.data.abbrlink || post.slug}/`}>{post.data.title}</a>
|
||||
{/* Post Date */}
|
||||
<time class="block text-5.6 leading-7 font-navbar opacity-30 lg:inline lg:before:content-['_']">
|
||||
{post.data.published.toLocaleDateString('en-US', { month: '2-digit', day: '2-digit' }).replace('/', '-')}
|
||||
|
|
|
@ -27,7 +27,7 @@ const allTags = await getAllTags()
|
|||
<ul>
|
||||
{posts.map(post => (
|
||||
<li>
|
||||
<a href={`/${lang}/posts/${post.data.slug || post.slug}/`}>{post.data.title}</a>
|
||||
<a href={`/${lang}/posts/${post.data.abbrlink || post.slug}/`}>{post.data.title}</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
|
|
@ -28,7 +28,7 @@ const { Content, remarkPluginFrontmatter } = await post.render()
|
|||
<article class="heti mb-12.6">
|
||||
<h1 class="post-title">
|
||||
<span
|
||||
transition:name={`post-${post.data.slug || post.slug}`}
|
||||
transition:name={`post-${post.data.abbrlink || post.slug}`}
|
||||
data-disable-transition-on-theme
|
||||
>
|
||||
{post.data.title}
|
||||
|
@ -37,7 +37,7 @@ const { Content, remarkPluginFrontmatter } = await post.render()
|
|||
|
||||
<div
|
||||
class="mb-17 block c-primary font-time"
|
||||
transition:name={`time-${post.data.slug || post.slug}`}
|
||||
transition:name={`time-${post.data.abbrlink || post.slug}`}
|
||||
data-disable-transition-on-theme
|
||||
>
|
||||
<time>
|
||||
|
|
|
@ -25,7 +25,7 @@ export async function checkSlugDuplication(posts: Post[]): Promise<string[]> {
|
|||
|
||||
posts.forEach((post) => {
|
||||
const lang = post.data.lang || ''
|
||||
const slug = post.data.slug || post.slug
|
||||
const slug = post.data.abbrlink || post.slug
|
||||
|
||||
if (!slugMap.has(lang)) {
|
||||
slugMap.set(lang, new Set())
|
||||
|
|
|
@ -20,7 +20,14 @@ export function getLangFromPath(path: string) {
|
|||
export function getLocalizedPath(path: string, currentLang?: string) {
|
||||
const clean = cleanPath(path)
|
||||
const lang = currentLang || getLangFromPath(path)
|
||||
return lang === defaultLocale ? `/${clean}` : `/${lang}/${clean}`
|
||||
|
||||
// 如果是根目录(clean为空),则返回/
|
||||
if (clean === '') {
|
||||
return lang === defaultLocale ? '/' : `/${lang}/`
|
||||
}
|
||||
|
||||
// 其他路径正常处理
|
||||
return lang === defaultLocale ? `/${clean}/` : `/${lang}/${clean}/`
|
||||
}
|
||||
|
||||
export function isHomePage(path: string) {
|
||||
|
@ -55,3 +62,27 @@ export function getPagePath(path: string) {
|
|||
getLocalizedPath: (targetPath: string) => getLocalizedPath(targetPath, currentLang),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取特定文章支持的语言列表
|
||||
* @param post 文章对象
|
||||
* @returns 该文章支持的语言数组,如果未指定则返回所有配置语言
|
||||
*/
|
||||
export function getAvailableLanguages(post?: { data?: { lang?: string } }) {
|
||||
// 默认支持所有配置的语言
|
||||
const defaultLangs = ['', ...themeConfig.global.moreLocale]
|
||||
|
||||
// 如果没有提供文章对象,返回所有语言
|
||||
if (!post || !post.data) {
|
||||
return defaultLangs
|
||||
}
|
||||
|
||||
// 确定文章支持的语言
|
||||
if (post.data.lang && typeof post.data.lang === 'string' && post.data.lang.trim() !== '') {
|
||||
// 如果lang是字符串
|
||||
return ['', post.data.lang]
|
||||
}
|
||||
|
||||
// 如果没有指定或格式不对,返回所有语言
|
||||
return defaultLangs
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
import type { CollectionEntry } from 'astro:content'
|
||||
import { themeConfig } from '@/config'
|
||||
|
||||
// 获取默认语言
|
||||
const defaultLocale = themeConfig.global.locale
|
||||
|
||||
export function generateLanguagePaths() {
|
||||
return themeConfig.global.moreLocale.map(lang => ({
|
||||
params: { lang },
|
||||
|
@ -10,29 +13,77 @@ export function generateLanguagePaths() {
|
|||
export function generatePostPaths(posts: CollectionEntry<'posts'>[]) {
|
||||
return posts.map(post => ({
|
||||
params: {
|
||||
slug: post.data.slug || post.slug,
|
||||
slug: post.data.abbrlink || post.slug,
|
||||
},
|
||||
props: { post },
|
||||
}))
|
||||
}
|
||||
|
||||
export function generateMultiLangPostPaths(posts: CollectionEntry<'posts'>[]) {
|
||||
return themeConfig.global.moreLocale.flatMap(lang =>
|
||||
posts.map(post => ({
|
||||
params: {
|
||||
lang,
|
||||
slug: post.data.slug || post.slug,
|
||||
},
|
||||
props: { post },
|
||||
})),
|
||||
)
|
||||
interface PathResult {
|
||||
params: {
|
||||
lang: string
|
||||
slug: string
|
||||
}
|
||||
props: {
|
||||
post: CollectionEntry<'posts'>
|
||||
}
|
||||
}
|
||||
|
||||
const result: PathResult[] = []
|
||||
|
||||
posts.forEach((post) => {
|
||||
// 确定这篇文章应该生成哪些语言版本
|
||||
let postLangs: string[] = themeConfig.global.moreLocale
|
||||
|
||||
if (post.data.lang && typeof post.data.lang === 'string' && post.data.lang.trim() !== '') {
|
||||
// 如果lang是单个字符串,转为数组
|
||||
postLangs = [post.data.lang]
|
||||
}
|
||||
|
||||
// 处理非默认语言的路径
|
||||
postLangs.forEach((lang) => {
|
||||
// 跳过默认语言,它将通过 generatePostPaths 生成
|
||||
if (lang !== defaultLocale) {
|
||||
result.push({
|
||||
params: {
|
||||
lang,
|
||||
slug: post.data.abbrlink || post.slug,
|
||||
},
|
||||
props: { post },
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 如果文章支持默认语言,则生成无语言代码的路径
|
||||
// 默认语言条件:未指定lang属性,或lang属性等于defaultLocale
|
||||
const supportsDefaultLang = !post.data.lang
|
||||
|| (typeof post.data.lang === 'string' && post.data.lang === defaultLocale)
|
||||
|
||||
if (supportsDefaultLang) {
|
||||
// 默认语言的路径不包含语言代码,在这里用特殊参数标记
|
||||
// 这将由 [slug].astro 页面处理,不在URL中显示语言代码
|
||||
result.push({
|
||||
params: {
|
||||
lang: 'default',
|
||||
slug: post.data.abbrlink || post.slug,
|
||||
},
|
||||
props: { post },
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
export function generateMultiLangTagPaths(tags: string[]) {
|
||||
return themeConfig.global.moreLocale.flatMap(lang =>
|
||||
tags.map(tag => ({
|
||||
params: { lang, tag },
|
||||
props: { tag },
|
||||
})),
|
||||
// 跳过默认语言,它将通过其他路径生成
|
||||
lang !== defaultLocale
|
||||
? tags.map(tag => ({
|
||||
params: { lang, tag },
|
||||
props: { tag },
|
||||
}))
|
||||
: [],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ export async function generateRSS({ lang }: GenerateRSSOptions = {}) {
|
|||
description: post.data.description || getExcerpt(post.body),
|
||||
// Generate absolute URL with optional language prefix
|
||||
link: new URL(
|
||||
`${lang ? `${lang}/` : ''}posts/${post.data.slug || post.slug}/`,
|
||||
`${lang ? `${lang}/` : ''}posts/${post.data.abbrlink || post.slug}/`,
|
||||
url,
|
||||
).toString(),
|
||||
// Convert markdown content to HTML, allowing img tags
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue