Skip to content

Commit

Permalink
add useI18n composable
Browse files Browse the repository at this point in the history
  • Loading branch information
Haberkamp committed Oct 1, 2024
1 parent ea9a181 commit dd51e31
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 4 deletions.
22 changes: 22 additions & 0 deletions packages/component-library/src/components/form/my-i18n/my-i18n.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
{{ t("foo.bar") }}
</template>

<script setup lang="ts">
import { useI18n } from "@/utils/i18n";
const { t } = useI18n({
messages: {
de: {
foo: {
bar: "Hallo Welt",
},
},
en: {
foo: {
bar: "Hello World",
},
},
},
});
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
</template>

<script setup lang="ts">
import { provideI18n } from "@/composables/useI18n";
import { type FutureFlags, provideFutureFlags } from "../../composables/useFutureFlags";
type Props = {
const props = defineProps<{
future?: FutureFlags;
};
const props = defineProps<Props>();
locale?: string;
}>();
provideFutureFlags(props.future);
provideI18n(props.locale);
</script>
34 changes: 34 additions & 0 deletions packages/component-library/src/composables/useI18n.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { render, screen } from "@testing-library/vue";
import { useI18n } from "./useI18n";

describe("useI18n", () => {
it("returns the translation for the given path", () => {
render({
setup() {
const { t } = useI18n({
messages: { en: { greeting: "Hello!" } },
});

return { t };
},
template: "{{ t('greeting') }}",
});

expect(screen.getByText("Hello!")).toBeInTheDocument();
});

it("returns the path to the translation if no translation is found", () => {
render({
setup() {
const { t } = useI18n({
messages: { en: { greeting: "Hello!" } },
});

return { t };
},
template: "{{ t('path.to.translation') }}",
});

expect(screen.getByText("path.to.translation")).toBeInTheDocument();
});
});
53 changes: 53 additions & 0 deletions packages/component-library/src/composables/useI18n.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { provide, inject } from "vue";

function get(obj: Record<string, unknown>, path: string) {
if (typeof obj !== "object" || obj === null) return undefined;

const keys = path.split(".");
let result = obj;

for (const key of keys) {
if (result === undefined || result === null) return undefined;

// @ts-ignore
result = result[key];
}

return result;
}

interface TranslationDictionary {
[key: string]: string | TranslationDictionary;
}

type Options = { messages: TranslationDictionary };

const defaultI18nState = {
locale: "en",
defaultLocale: "en",
};

const i18nInjectionKey = Symbol("mt-i18n");

export function provideI18n(locale: string = "en") {
const state = {
...defaultI18nState,
locale: locale,
};

provide(i18nInjectionKey, state);
}

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();

const fallback = get(messages, `${i18n.defaultLocale}.${path}`);
return fallback ? fallback.toString() : path;
}

return { t: translate };
}

0 comments on commit dd51e31

Please sign in to comment.