mirror of
https://github.com/directus/directus.git
synced 2026-04-03 03:00:39 -04:00
Fix special characters in translation strings (#15872)
* Fix special characters in translation strings * unit test Co-authored-by: Brainslug <br41nslug@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { ref, Ref } from 'vue';
|
||||
import api from '@/api';
|
||||
import { getLiteralInterpolatedTranslation } from '@/utils/get-literal-interpolated-translation';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import { Language, i18n } from '@/lang';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
@@ -126,7 +127,7 @@ export function useTranslationStrings(): UsableTranslationStrings {
|
||||
if (!cur.key || !cur.translations) return acc;
|
||||
const translationForCurrentLang = cur.translations.find((t) => t.language === lang);
|
||||
if (!translationForCurrentLang || !translationForCurrentLang.translation) return acc;
|
||||
return { ...acc, [cur.key]: translationForCurrentLang.translation };
|
||||
return { ...acc, [cur.key]: getLiteralInterpolatedTranslation(translationForCurrentLang.translation) };
|
||||
}, {});
|
||||
i18n.global.mergeLocaleMessage(lang, localeMessages);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Collection as CollectionRaw, DeepPartial, Field } from '@directus/share
|
||||
import { Collection } from '@/types/collections';
|
||||
import { getCollectionType } from '@directus/shared/utils';
|
||||
import { notify } from '@/utils/notify';
|
||||
import { getLiteralInterpolatedTranslation } from '@/utils/get-literal-interpolated-translation';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import formatTitle from '@directus/format-title';
|
||||
import { defineStore } from 'pinia';
|
||||
@@ -56,24 +57,28 @@ export const useCollectionsStore = defineStore({
|
||||
for (let i = 0; i < collection.meta.translations.length; i++) {
|
||||
const { language, translation, singular, plural } = collection.meta.translations[i];
|
||||
|
||||
const literalInterpolatedTranslation = translation ? translation.replace(/([{}@$|])/g, "{'$1'}") : null;
|
||||
|
||||
i18n.global.mergeLocaleMessage(language, {
|
||||
...(literalInterpolatedTranslation && {
|
||||
collection_names: {
|
||||
[collection.collection]: literalInterpolatedTranslation,
|
||||
},
|
||||
}),
|
||||
...(singular && {
|
||||
collection_names_singular: {
|
||||
[collection.collection]: singular,
|
||||
},
|
||||
}),
|
||||
...(plural && {
|
||||
collection_names_plural: {
|
||||
[collection.collection]: plural,
|
||||
},
|
||||
}),
|
||||
...(translation
|
||||
? {
|
||||
collection_names: {
|
||||
[collection.collection]: getLiteralInterpolatedTranslation(translation),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(singular
|
||||
? {
|
||||
collection_names_singular: {
|
||||
[collection.collection]: getLiteralInterpolatedTranslation(singular),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(plural
|
||||
? {
|
||||
collection_names_plural: {
|
||||
[collection.collection]: getLiteralInterpolatedTranslation(plural),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import api from '@/api';
|
||||
import { i18n } from '@/lang';
|
||||
import { useCollectionsStore } from '@/stores/collections';
|
||||
import { useRelationsStore } from '@/stores/relations';
|
||||
import { getLiteralInterpolatedTranslation } from '@/utils/get-literal-interpolated-translation';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import formatTitle from '@directus/format-title';
|
||||
import { DeepPartial, Field, FieldRaw, Relation } from '@directus/shared/types';
|
||||
@@ -75,17 +76,16 @@ export const useFieldsStore = defineStore({
|
||||
for (let i = 0; i < field.meta.translations.length; i++) {
|
||||
const { language, translation } = field.meta.translations[i];
|
||||
|
||||
// Interpolate special characters in vue-i18n to prevent parsing error. Ref #11287
|
||||
const literalInterpolatedTranslation = translation ? translation.replace(/([{}@$|])/g, "{'$1'}") : null;
|
||||
|
||||
i18n.global.mergeLocaleMessage(language, {
|
||||
...(literalInterpolatedTranslation && {
|
||||
fields: {
|
||||
[field.collection]: {
|
||||
[field.field]: literalInterpolatedTranslation,
|
||||
},
|
||||
},
|
||||
}),
|
||||
...(translation
|
||||
? {
|
||||
fields: {
|
||||
[field.collection]: {
|
||||
[field.field]: getLiteralInterpolatedTranslation(translation),
|
||||
},
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
10
app/src/utils/get-literal-interpolated-translation.test.ts
Normal file
10
app/src/utils/get-literal-interpolated-translation.test.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { getLiteralInterpolatedTranslation } from '@/utils/get-literal-interpolated-translation';
|
||||
|
||||
test('No special characters', () => {
|
||||
expect(getLiteralInterpolatedTranslation('folding at home')).toBe('folding at home');
|
||||
});
|
||||
|
||||
test('With special characters', () => {
|
||||
expect(getLiteralInterpolatedTranslation('folding@home')).toBe(`folding{'@'}home`);
|
||||
});
|
||||
11
app/src/utils/get-literal-interpolated-translation.ts
Normal file
11
app/src/utils/get-literal-interpolated-translation.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Literal interpolation to use special characters such as "{", "}", "@", "$", and "|" in app translations
|
||||
*
|
||||
* @param translation - vue i18n translation string
|
||||
* @returns - literal interpolated translation string
|
||||
*
|
||||
* @see {@link https://github.com/directus/directus/pull/11287}
|
||||
*/
|
||||
export function getLiteralInterpolatedTranslation(translation: string) {
|
||||
return translation.replace(/([{}@$|])/g, "{'$1'}");
|
||||
}
|
||||
Reference in New Issue
Block a user