1import { createResource } from "frappe-ui";
2import { ref } from "vue";
3import type { App } from "vue";
4
5// Ref, so `__()` text re-renders on language change.
6export const translations = ref<Record<string, string>>({});
7
8type Replacement = string | number;
9
10function translate(message: string): string;
11function translate(message: string, ...args: Replacement[]): string;
12function translate(message: string, args: Replacement[]): string;
13function translate(
14 message: string,
15 ...args: (Replacement | Replacement[])[]
16): string {
17 const translatedMessage = translations.value[message] || message;
18 const values = args.flat();
19 if (values.length === 0) {
20 return translatedMessage;
21 }
22 return translatedMessage.replace(/{(\d+)}/g, function (match, index) {
23 const value = values[Number(index)];
24 return value === undefined ? match : String(value);
25 });
26}
27
28export const __ = translate;
29
30let resource: ReturnType<typeof createResource> | null = null;
31
32// Later calls refetch, e.g. after a language change.
33export function fetchTranslations() {
34 if (resource) return resource.reload();
35 resource = createResource({
36 url: "opendesk.api.general.get_translations",
37 method: "GET",
38 cache: "translations",
39 auto: true,
40 transform(data: Record<string, string>) {
41 translations.value = data || {};
42 return data;
43 },
44 });
45}
46
47export function translationPlugin(app: App<Element>) {
48 app.config.globalProperties.__ = translate;
49 (window as any).__ = translate;
50 fetchTranslations();
51}
52