diff --git a/packages/component-library/src/composables/useI18n.spec.ts b/packages/component-library/src/composables/useI18n.spec.ts index f739cfa6..e305493f 100644 --- a/packages/component-library/src/composables/useI18n.spec.ts +++ b/packages/component-library/src/composables/useI18n.spec.ts @@ -31,4 +31,34 @@ describe("useI18n", () => { expect(screen.getByText("path.to.translation")).toBeInTheDocument(); }); + + it("translates the snippet with custom values", () => { + render({ + setup() { + const { t } = useI18n({ + messages: { en: { greeting: "Hello, {name}!" } }, + }); + + return { t }; + }, + template: "{{ t('greeting', { name: 'World' }) }}", + }); + + expect(screen.getByText("Hello, World!")).toBeInTheDocument(); + }); + + it("keeps the custom value syntax when no custom value is provided", () => { + render({ + setup() { + const { t } = useI18n({ + messages: { en: { greeting: "Hello, {name}!" } }, + }); + + return { t }; + }, + template: "{{ t('greeting') }}", + }); + + expect(screen.getByText("Hello, {name}!")).toBeInTheDocument(); + }); }); diff --git a/packages/component-library/src/composables/useI18n.ts b/packages/component-library/src/composables/useI18n.ts index f8ac95ef..afc4426a 100644 --- a/packages/component-library/src/composables/useI18n.ts +++ b/packages/component-library/src/composables/useI18n.ts @@ -1,6 +1,6 @@ import { provide, inject } from "vue"; -function get(obj: Record, path: string) { +function get(obj: Record, path: string): string | undefined { if (typeof obj !== "object" || obj === null) return undefined; const keys = path.split("."); @@ -13,6 +13,7 @@ function get(obj: Record, path: string) { result = result[key]; } + // @ts-ignore return result; } @@ -38,15 +39,22 @@ export function provideI18n(locale: string = "en") { provide(i18nInjectionKey, state); } +const CUSTOM_VALUE_REGEX = /{([^}]*)}/g; + export function useI18n({ messages }: Options) { const i18n = inject(i18nInjectionKey, defaultI18nState); - function translate(path: string): string { - const translation = get(messages, `${i18n.locale}.${path}`); - if (translation) return translation.toString(); + function translate(path: string, customValues: Record = {}): string { + const translation = + get(messages, `${i18n.locale}.${path}`) || get(messages, `${i18n.defaultLocale}.${path}`); + + if (!translation) return path; - const fallback = get(messages, `${i18n.defaultLocale}.${path}`); - return fallback ? fallback.toString() : path; + return translation.replace(CUSTOM_VALUE_REGEX, (match: string, key: string) => { + return Object.prototype.hasOwnProperty.call(customValues, key) + ? customValues[key].toString() + : match; + }); } return { t: translate };