Skip to content

Commit a5d17ff

Browse files
committed
feat: introduce primary language support for translations
1 parent 1f990da commit a5d17ff

6 files changed

Lines changed: 44 additions & 25 deletions

File tree

custom/LanguageEveryPageLoader.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
<script setup>
44
import { onMounted } from 'vue';
55
import { useI18n } from 'vue-i18n';
6-
import { setLang, getLocalLang } from './langCommon';
6+
import { setLang, getLocalLang, setLocalLang } from './langCommon';
77
88
const { setLocaleMessage, locale } = useI18n();
99
1010
const props = defineProps(['meta']);
1111
1212
onMounted(() => {
13-
setLang({ setLocaleMessage, locale }, props.meta.pluginInstanceId, getLocalLang(props.meta.supportedLanguages));
13+
const langIso = getLocalLang(props.meta.supportedLanguages, props.meta.primaryLanguage);
14+
setLocalLang(langIso);
15+
setLang({ setLocaleMessage, locale }, props.meta.pluginInstanceId, langIso);
1416
});
1517
</script>

custom/LanguageInUserMenu.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,6 @@ const selectedOption = computed(() => {
8888
8989
9090
onMounted(() => {
91-
selectedLanguage.value = getLocalLang(props.meta.supportedLanguages);
91+
selectedLanguage.value = getLocalLang(props.meta.supportedLanguages, props.meta.primaryLanguage);
9292
});
9393
</script>

custom/LanguageUnderLogin.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,6 @@ const options = computed(() => {
6262
});
6363
6464
onMounted(() => {
65-
selectedLanguage.value = getLocalLang(props.meta.supportedLanguages);
65+
selectedLanguage.value = getLocalLang(props.meta.supportedLanguages, props.meta.primaryLanguage);
6666
});
6767
</script>

custom/langCommon.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import dayjsLocales from './dayjsLocales';
44
import datepickerLocales from './datepickerLocales';
55
import dayjs from 'dayjs';
66
import Datepicker from "flowbite-datepicker/Datepicker";
7+
import type { SupportedLanguage } from '../types';
78

89

910
const messagesCache: Record<
@@ -88,7 +89,7 @@ export function getCountryCodeFromLangCode(langCode) {
8889

8990
const LS_LANG_KEY = `afLanguage`;
9091

91-
export function getLocalLang(supportedLanguages: {code}[]): string {
92+
export function getLocalLang(supportedLanguages: {code}[], primaryLanguage?: SupportedLanguage): string {
9293
let lsLang = localStorage.getItem(LS_LANG_KEY);
9394
// if someone screwed up the local storage or we stopped language support, lets check if it is in supported languages
9495
if (lsLang && !supportedLanguages.find((l) => l.code == lsLang)) {
@@ -103,6 +104,10 @@ export function getLocalLang(supportedLanguages: {code}[]): string {
103104
if (foundLang) {
104105
return foundLang.code;
105106
}
107+
if (primaryLanguage && supportedLanguages.find((l) => l.code == primaryLanguage)) {
108+
return primaryLanguage;
109+
}
110+
106111
return supportedLanguages[0].code;
107112
}
108113

index.ts

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,14 @@ export default class I18nPlugin extends AdminForthPlugin {
117117

118118
// sorted by name list of all supported languages, without en e.g. 'al|ro|uk'
119119
fullCompleatedFieldValue: string;
120+
primaryLanguage: SupportedLanguage;
120121

121122
constructor(options: PluginOptions) {
122123
super(options, import.meta.url);
123124
this.options = options;
124125
this.cache = new CachingAdapterMemory();
125126
this.trFieldNames = {};
127+
this.primaryLanguage = options.primaryLanguage || 'en';
126128
}
127129

128130
async computeCompletedFieldValue(record: any) {
@@ -290,6 +292,7 @@ export default class I18nPlugin extends AdminForthPlugin {
290292
const compMeta = {
291293
brandSlug: adminforth.config.customization.brandNameSlug,
292294
pluginInstanceId: this.pluginInstanceId,
295+
primaryLanguage: this.primaryLanguage,
293296
supportedLanguages: this.options.supportedLanguages.map(lang => (
294297
{
295298
code: lang,
@@ -522,20 +525,20 @@ export default class I18nPlugin extends AdminForthPlugin {
522525
const requestSlavicPlurals = Object.keys(SLAVIC_PLURAL_EXAMPLES).includes(primaryLang) && plurals;
523526
const region = String(lang).split('-')[1]?.toUpperCase() || '';
524527
const prompt = `
525-
I need to translate strings in JSON to ${langName} language (ISO 639-1 code ${lang}) from English for my web app.
526-
${region ? `Use the regional conventions for ${lang} (region ${region}), including spelling, punctuation, and formatting.` : ''}
527-
${requestSlavicPlurals ? `You should provide 4 slavic forms (in format "zero count | singular count | 2-4 | 5+") e.g. "apple | apples" should become "${SLAVIC_PLURAL_EXAMPLES[lang]}"` : ''}
528-
Keep keys, as is, write translation into values! If keys have variables (in curly brackets), then translated strings should have them as well (variables itself should not be translated). Here are the strings:
529-
530-
\`\`\`json
531-
${
532-
JSON.stringify(strings.reduce((acc: object, s: { en_string: string }): object => {
533-
acc[s.en_string] = '';
534-
return acc;
535-
}, {}), null, 2)
536-
}
537-
\`\`\`
538-
`;
528+
I need to translate strings in JSON to ${langName} language (ISO 639-1 code ${lang}) from English for my web app.
529+
${region ? `Use the regional conventions for ${lang} (region ${region}), including spelling, punctuation, and formatting.` : ''}
530+
${requestSlavicPlurals ? `You should provide 4 slavic forms (in format "zero count | singular count | 2-4 | 5+") e.g. "apple | apples" should become "${SLAVIC_PLURAL_EXAMPLES[lang]}"` : ''}
531+
Keep keys, as is, write translation into values! If keys have variables (in curly brackets), then translated strings should have them as well (variables itself should not be translated). Here are the strings:
532+
533+
\`\`\`json
534+
${
535+
JSON.stringify(strings.reduce((acc: object, s: { en_string: string }): object => {
536+
acc[s.en_string] = '';
537+
return acc;
538+
}, {}), null, 2)
539+
}
540+
\`\`\`
541+
`;
539542

540543
// call OpenAI
541544
const resp = await this.options.completeAdapter.complete(
@@ -803,13 +806,13 @@ export default class I18nPlugin extends AdminForthPlugin {
803806
}
804807
// console.log('🪲tr', msg, category, lang);
805808

806-
// if lang is not supported , throw
809+
// if lang is not supported, fallback to primaryLanguage, then to english
807810
if (!this.options.supportedLanguages.includes(lang as SupportedLanguage)) {
808-
lang = 'en'; // for now simply fallback to english
809-
810-
// throwing like line below might be too strict, e.g. for custom apis made with fetch which don't pass accept-language
811-
// throw new Error(`Language ${lang} is not entered to be supported by requested by browser in request headers accept-language`);
811+
lang = this.primaryLanguage; // fallback to primary language first
812+
if (!this.options.supportedLanguages.includes(lang as SupportedLanguage)) {
813+
lang = 'en'; // final fallback to english
812814
}
815+
}
813816

814817
let result;
815818
// try to get translation from cache
@@ -907,7 +910,8 @@ export default class I18nPlugin extends AdminForthPlugin {
907910
const translations = {};
908911
const allTranslations = await resource.list([Filters.EQ(this.options.categoryFieldName, category)]);
909912
for (const tr of allTranslations) {
910-
translations[tr[this.enFieldName]] = tr[this.trFieldNames[lang]];
913+
const translatedValue = tr[this.trFieldNames[lang]];
914+
translations[tr[this.enFieldName]] = translatedValue || tr[this.enFieldName];
911915
}
912916
await this.cache.set(cacheKey, translations);
913917
return translations;

types.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,12 @@ export interface PluginOptions {
5555
* it should be a JSON field (underlyng database type should be TEXT or JSON)
5656
*/
5757
reviewedCheckboxesFieldName?: string;
58+
59+
/**
60+
* Primary language for the application. This is the default language shown to users.
61+
* English is always used as the source language for translations, even if primaryLanguage is different.
62+
* When a translation is missing for the primaryLanguage, English will be shown as fallback.
63+
* Defaults to 'en' if not specified.
64+
*/
65+
primaryLanguage?: SupportedLanguage;
5866
}

0 commit comments

Comments
 (0)