diff --git a/.github/translation-guidance.json b/.github/translation-guidance.json index 56188ec4d..688f06591 100644 --- a/.github/translation-guidance.json +++ b/.github/translation-guidance.json @@ -314,6 +314,122 @@ } ] }, + "kk": { + "context": { + "localeName": "қазақ тілі (Қазақстан)", + "audience": "Kazakh-speaking Web3 developers and institutional finance operators in Kazakhstan", + "conventions": [ + "Use contemporary professional Kazakh that is natural in a product interface.", + "Prefer clear native Kazakh terminology over unnecessary Russian or English loanwords.", + "Keep established protocol names, product names, abbreviations and code identifiers unchanged." + ] + }, + "instructions": [ + "Use a respectful tone and address the user with Сіз when direct address is necessary.", + "Prefer concise action labels and neutral, descriptive status messages.", + "Choose terminology from the approved glossary consistently across catalog namespaces.", + "Preserve the meaning and grammatical role of every placeholder exactly." + ], + "terminology": [ + { + "source": "token / wallet / asset", + "preferred": "токен / әмиян / актив" + }, + { + "source": "counterparty", + "preferred": "қарсы тарап", + "avoid": "контрагент / қарсылас / қарсы агент" + }, + { + "source": "compliance", + "preferred": "талаптарға сәйкестік", + "avoid": "комплаенс" + }, + { + "source": "on-chain / off-chain", + "preferred": "блокчейн арқылы or блокчейнде / блокчейннен тыс", + "note": "Choose the grammatical form that fits the sentence." + }, + { + "source": "tokenized", + "preferred": "токенге айналдырылған", + "avoid": "токенделген / токенизацияланған" + }, + { + "source": "transfer / payment / provider / quote", + "preferred": "аударым / төлем / провайдер / баға ұсынысы" + }, + { + "source": "custody / issuance / approval / policy", + "preferred": "сақтау / шығару / мақұлдау / саясат", + "note": "Use a more descriptive phrase when a short noun would be ambiguous in context." + }, + { + "source": "stablecoin / blockchain / staking / airdrop", + "preferred": "стейблкоин / блокчейн / стейкинг / эйрдроп" + }, + { + "source": "API / RPC / webhook / Solana / SPL / USDC", + "preferred": "Keep these technical terms unchanged." + } + ], + "forbiddenTerms": [ + { + "label": "контрагент", + "pattern": "контрагент", + "flags": "iu", + "preferred": "қарсы тарап" + }, + { + "label": "комплаенс", + "pattern": "комплаенс", + "flags": "iu", + "preferred": "талаптарға сәйкестік" + }, + { + "label": "literal token variants", + "pattern": "(?:жетон|таңбалауыш|токендел|токенизац|таңбаланған)", + "flags": "iu", + "preferred": "токен / токенге айналдырылған" + }, + { + "label": "жалбыз", + "pattern": "жалбыз", + "flags": "iu", + "preferred": "шығару / токен шығару мекенжайы" + }, + { + "label": "mint as money or currency", + "pattern": "ақша мекенжай|теңге сарай|Актив немесе теңге", + "flags": "iu", + "preferred": "токен шығару мекенжайы" + }, + { + "label": "API перне", + "pattern": "API перне", + "flags": "iu", + "preferred": "API кілті" + }, + { + "label": "стабилкоин / стабелькоин", + "pattern": "стабилкоин|стабелькоин", + "flags": "iu", + "preferred": "стейблкоин" + }, + { + "label": "informal сен address", + "pattern": "(?; + +const kkMessages = mergeLocalizedMessages(enMessages, kkCatalog); + const ptCatalog = { ...pt, ...ptDashboardApprovals, @@ -118,6 +150,20 @@ const ptCatalog = { const ptMessages = mergeLocalizedMessages(enMessages, ptCatalog); +const ruCatalog = { + ...ru, + ...ruDashboardApprovals, + ...ruDashboardCustody, + ...ruDashboardEarn, + ...ruDashboardIssuance, + ...ruDashboardPayments, + ...ruDashboardPolicies, + ...ruDashboardPrivateChannels, + Shared: ruShared, +} satisfies LocalizedMessages; + +const ruMessages = mergeLocalizedMessages(enMessages, ruCatalog); + export type MessageKeyFor = TValue extends string ? "" : { @@ -133,7 +179,9 @@ const messagesByLocale: Record = { en: enMessages, es: esMessages, fr: frMessages, + kk: kkMessages, pt: ptMessages, + ru: ruMessages, }; export function getMessages(locale: AppLocale): Messages { diff --git a/apps/sdp-web/src/i18n/messages.unit.test.ts b/apps/sdp-web/src/i18n/messages.unit.test.ts index d401589c7..463574d49 100644 --- a/apps/sdp-web/src/i18n/messages.unit.test.ts +++ b/apps/sdp-web/src/i18n/messages.unit.test.ts @@ -16,13 +16,14 @@ function flattenKeys(value: unknown, prefix = ""): string[] { return flattenKeys(nested, next); }); } - describe("i18n messages", () => { it("only accepts configured locales", () => { expect(isAppLocale("en")).toBe(true); expect(isAppLocale("es")).toBe(true); expect(isAppLocale("fr")).toBe(true); + expect(isAppLocale("kk")).toBe(true); expect(isAppLocale("pt")).toBe(true); + expect(isAppLocale("ru")).toBe(true); expect(isAppLocale("de")).toBe(false); }); @@ -31,6 +32,10 @@ describe("i18n messages", () => { expect(translate(getMessages("es"), "Home.contactUs")).toBe("Contáctanos"); expect(translate(getMessages("fr"), "Home.contactUs")).toBe("Nous contacter"); expect(translate(getMessages("pt"), "Home.contactUs")).toBe("Fale conosco"); + expect(translate(getMessages("kk"), "Home.joinWaitlist")).toBe("Күту тізіміне қосылу"); + expect(translate(getMessages("ru"), "Home.joinWaitlist")).toBe( + "Присоединиться к списку ожидания" + ); }); it("keeps non-English catalogs inventory-matched to English", () => {