orca/config/scripts/locale-generic-ui-terms.mjs

103 lines
3.2 KiB
JavaScript

// Ordinary UI vocabulary that reads like a brand but is not one. Every locale should translate
// these, so the policy must neither pin the whole value to English nor revert the translation
// inside a sentence. The product-name homonyms (Continue.dev, the agent entries) stay Latin
// through ENGLISH_ONLY_KEY_PREFIXES, which matches on the catalog key rather than the word.
// Renderings a locale is expected to use. They are translations, never machine-translation
// errors, so a brand revert must leave them alone. Nonsense forms that share the same English
// term (zh 回购 "repurchase agreement", ja 端子 "electrical connector", es "Comprometerse")
// stay in BRAND_MISTRANSLATIONS and keep getting reverted.
const GENERIC_TERM_FAMILIES = [
{
terms: ['Agent', 'Agents', 'agent', 'agents'],
renderings: {
ko: ['에이전트'],
ja: ['エージェント'],
zh: ['代理', '智能体'],
es: ['Agente', 'agente', 'Agentes', 'agentes']
}
},
{
terms: ['Commit', 'Commits', 'commit', 'commits'],
renderings: {
ko: ['커밋'],
ja: ['コミット'],
zh: ['提交'],
es: [
'Confirmación',
'confirmación',
'Confirmaciones',
'confirmaciones',
'Confirmar',
'confirmar'
]
}
},
{
terms: ['Continue'],
renderings: {
ko: ['계속하다', '계속'],
ja: ['続ける', '続行'],
zh: ['继续'],
es: ['Continuar', 'continuar']
}
},
{
terms: ['Repo', 'Repos', 'repo', 'repos'],
renderings: {
ko: ['저장소', '레포'],
ja: ['リポジトリ', 'リポ'],
zh: ['存储库', '仓库'],
es: ['Repositorio', 'repositorio', 'Repositorios', 'repositorios']
}
},
{
terms: ['Terminal', 'Terminals', 'terminal', 'terminals'],
renderings: {
ko: ['터미널'],
ja: ['ターミナル'],
zh: ['终端'],
es: ['Terminales', 'terminales']
}
}
]
export const LOCALIZABLE_GENERIC_TERMS = new Set(
GENERIC_TERM_FAMILIES.flatMap((family) => family.terms)
)
const RENDERINGS_BY_TERM = new Map(
GENERIC_TERM_FAMILIES.flatMap((family) => family.terms.map((term) => [term, family.renderings]))
)
export function isLocalizableGenericTerm(term) {
return LOCALIZABLE_GENERIC_TERMS.has(term)
}
export function isCanonicalGenericRendering(term, locale, form) {
return RENDERINGS_BY_TERM.get(term)?.[locale]?.includes(form) ?? false
}
export function canonicalGenericRenderings(locale) {
return GENERIC_TERM_FAMILIES.flatMap((family) =>
(family.renderings[locale] ?? []).map((form) => ({ form, terms: family.terms }))
)
}
function spansOf(value, needle) {
const spans = []
for (let at = value.indexOf(needle); at !== -1; at = value.indexOf(needle, at + 1)) {
spans.push([at, at + needle.length])
}
return spans
}
// Why: zh 终端子进程 ("terminal sub-process") contains 端子, so a blind revert of the
// electrical-connector mistranslation would cut a valid word in half.
export function overlapsCanonicalRendering(term, locale, value, start, end) {
const renderings = RENDERINGS_BY_TERM.get(term)?.[locale] ?? []
return renderings.some((form) =>
spansOf(value, form).some(([from, to]) => start < to && from < end)
)
}