refactor(i18n): narrow link normalization

This commit is contained in:
pku-xht
2026-08-18 19:41:52 +08:00
parent 08ec2622b0
commit 1c253f7c5a
4 changed files with 17 additions and 27 deletions
+1 -9
View File
@@ -64,16 +64,8 @@ describe('translation link locale validation', () => {
})
})
it('normalizes an English extensionless file alias but retains a directory-index alias', () => {
it('retains an English directory-index alias', () => {
const root = fixture()
expect(translationLinkLocaleViolations(
'[Reference](reference)\n',
{ repoRoot: root, sourcePath: 'docs/guide.md' },
)[0]).toMatchObject({ expectedUrl: 'reference.md' })
expect(rewriteTranslationLinkLocales(
'[Reference](reference)\n',
{ repoRoot: root, sourcePath: 'docs/guide.md' },
).content).toBe('[Reference](reference.md)\n')
expect(translationLinkLocaleViolations(
'[Section](section/)\n',
{ repoRoot: root, sourcePath: 'docs/guide.md' },
+4 -12
View File
@@ -58,7 +58,7 @@ interface Replacement {
}
type LinkNode = Extract<Nodes, { type: 'link' | 'definition' }>
type ResolutionKind = 'exact' | 'extensionless' | 'directory-index'
type ResolutionKind = 'exact' | 'directory-index'
function decodePath(path: string): string {
try {
@@ -101,14 +101,8 @@ function resolveRepositoryTarget(
if (decoded.endsWith('/') && index !== undefined && repositoryFileExists(context, index)) {
return { path: index, kind: 'directory-index' }
}
if (posix.extname(decoded) === '') {
const markdown = repositoryRelativePath(`${exact}.md`)
if (markdown !== undefined && repositoryFileExists(context, markdown)) {
return { path: markdown, kind: 'extensionless' }
}
if (index !== undefined && repositoryFileExists(context, index)) {
return { path: index, kind: 'directory-index' }
}
if (posix.extname(decoded) === '' && index !== undefined && repositoryFileExists(context, index)) {
return { path: index, kind: 'directory-index' }
}
return undefined
}
@@ -142,7 +136,6 @@ function expectedLocalePath(
}
if (locale === 'en' && rawPath.endsWith('.zh.md')) return rawPath.replace(/\.zh\.md$/, '.md')
}
if (kind === 'extensionless') return `${rawPath}${locale === 'zh' ? '.zh.md' : '.md'}`
if (kind === 'directory-index' && locale === 'zh') {
return `${rawPath}${rawPath.endsWith('/') ? '' : '/'}index.zh.md`
}
@@ -177,8 +170,7 @@ function resolveTranslationLink(
}
function hasExpectedLocale(resolved: ResolvedTranslationLink): boolean {
if (resolved.targetPath !== resolved.expectedPath) return false
return !(resolved.locale === 'en' && resolved.kind === 'extensionless')
return resolved.targetPath === resolved.expectedPath
}
function replacementFor(destination: MarkdownDestination, value: string): Replacement {
+10 -2
View File
@@ -32,7 +32,11 @@ import {
} from './translation-pairing.ts'
function signature(markdown: string) {
return translationStructureSignature(parseTranslationMarkdown(markdown), 'counterpart.zh.md')
return translationStructureSignature(
parseTranslationMarkdown(markdown),
'counterpart.zh.md',
{ repoRoot: process.cwd(), sourcePath: 'counterpart.md', markdown },
)
}
function gitSupportsObjectFormat(format: 'sha256'): boolean {
@@ -189,7 +193,11 @@ describe('translation pairing switchers', () => {
)
expect(linksTo(canonical, targets)).toBe(true)
expect(translationStructureSignature(canonical, targets).links).toEqual([])
expect(translationStructureSignature(canonical, targets, {
repoRoot: process.cwd(),
sourcePath: 'python/sdk/README.md',
markdown: '[中文](https://github.com/deepseek-ai/deepseek-harness/blob/master/python/sdk/README.zh.md)',
}).links).toEqual([])
expect(linksTo(wrongPath, targets)).toBe(false)
})
})
+2 -4
View File
@@ -351,7 +351,7 @@ export function requiresSourceLanguageSwitcher(source: string): boolean {
export function translationStructureSignature(
tree: Nodes,
switcherTargets: string | readonly string[],
linkContext?: TranslationLinkContext & { markdown: string },
linkContext: TranslationLinkContext & { markdown: string },
): TranslationStructureSignature {
const acceptedSwitchers = new Set(
typeof switcherTargets === 'string' ? [switcherTargets] : switcherTargets,
@@ -364,9 +364,7 @@ export function translationStructureSignature(
}
collectDefinitions(tree)
const linkTarget = (node: Extract<Nodes, { type: 'link' | 'definition' }>): string => (
linkContext === undefined
? node.url
: semanticTranslationLinkNodeTarget(node, linkContext.markdown, linkContext)
semanticTranslationLinkNodeTarget(node, linkContext.markdown, linkContext)
)
const visit = (node: Nodes): void => {
switch (node.type) {