Skip to content

Commit

Permalink
Merge pull request #264 from BorisTB/master
Browse files Browse the repository at this point in the history
Support keyPrefix
  • Loading branch information
gilbsgilbs authored Dec 30, 2023
2 parents 5eb8f8b + 866d257 commit 8b303a6
Show file tree
Hide file tree
Showing 12 changed files with 107 additions and 3 deletions.
6 changes: 6 additions & 0 deletions src/extractors/getFixedTFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ export default function extractGetFixedTFunction(
const tBinding = id.scope.bindings[id.node.name];
if (!tBinding) return [];

const keyPrefixArgument = path.get('arguments')[2];
const keyPrefix: string | null = getFirstOrNull(
evaluateIfConfident(keyPrefixArgument),
);

let keys = Array<ExtractedKey>();
for (const reference of tBinding.referencePaths) {
if (
Expand All @@ -85,6 +90,7 @@ export default function extractGetFixedTFunction(
...k,
parsedOptions: {
...k.parsedOptions,
keyPrefix: k.parsedOptions.keyPrefix || keyPrefix,
ns: k.parsedOptions.ns || ns,
},
})),
Expand Down
7 changes: 7 additions & 0 deletions src/extractors/tFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ function parseTCallOptions(
contexts: false,
hasCount: false,
ns: null,
keyPrefix: null,
defaultValue: null,
};

Expand All @@ -76,6 +77,12 @@ function parseTCallOptions(
const defaultValueNodeValue = defaultValueNode.get('value');
res.defaultValue = evaluateIfConfident(defaultValueNodeValue);
}

const keyPrefixNode = findKeyInObjectExpression(path, 'keyPrefix');
if (keyPrefixNode !== null && keyPrefixNode.isObjectProperty()) {
const keyPrefixNodeValue = keyPrefixNode.get('value');
res.keyPrefix = evaluateIfConfident(keyPrefixNodeValue);
}
}

return res;
Expand Down
1 change: 1 addition & 0 deletions src/extractors/transComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ function parseTransComponentOptions(
const res: ExtractedKey['parsedOptions'] = {
contexts: false,
hasCount: false,
keyPrefix: null,
ns: null,
defaultValue: null,
};
Expand Down
10 changes: 10 additions & 0 deletions src/extractors/useTranslationHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ export default function extractUseTranslationHook(
const tBinding = id.scope.bindings['t'];
if (!tBinding) return [];

let keyPrefix: string | null = null;

const optionsArgument = path.get('arguments')[1];
const options = getFirstOrNull(evaluateIfConfident(optionsArgument));

if (options) {
keyPrefix = options.keyPrefix || keyPrefix;
}

let keys = Array<ExtractedKey>();
for (const reference of tBinding.referencePaths) {
if (
Expand All @@ -77,6 +86,7 @@ export default function extractUseTranslationHook(
...k,
parsedOptions: {
...k.parsedOptions,
keyPrefix: k.parsedOptions.keyPrefix || keyPrefix,
ns: k.parsedOptions.ns || ns,
},
})),
Expand Down
11 changes: 10 additions & 1 deletion src/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface I18NextParsedOptions {
contexts: string[] | boolean;
hasCount: boolean;
ns: string | null;
keyPrefix: string | null;
defaultValue: string | null;
}

Expand Down Expand Up @@ -49,6 +50,13 @@ export interface TranslationKey extends ExtractedKey {
function parseExtractedKey(key: ExtractedKey, config: Config): TranslationKey {
let cleanKey = key.key;

const keyPrefix = key.parsedOptions.keyPrefix;
if (keyPrefix) {
// Imitate behavior of i18next and just connect prefix with key before any other action
const keySeparator = config.keySeparator || '.';
cleanKey = `${keyPrefix}${keySeparator}${cleanKey}`;
}

let ns: string = key.parsedOptions.ns || config.defaultNS;
if (config.nsSeparator) {
const nsSeparatorPos = cleanKey.indexOf(config.nsSeparator);
Expand All @@ -60,9 +68,10 @@ function parseExtractedKey(key: ExtractedKey, config: Config): TranslationKey {
}

let keyPath = Array<string>();

if (config.keySeparator) {
const fullPath = cleanKey.split(config.keySeparator);
keyPath = fullPath.slice(0, fullPath.length - 1);
keyPath = [...keyPath, ...fullPath.slice(0, fullPath.length - 1)];
cleanKey = fullPath[fullPath.length - 1];
}

Expand Down
18 changes: 18 additions & 0 deletions tests/__fixtures__/testGetFixedTFunction/keyPrefix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import i18next from "i18next";

export function anyJSFunction1() {
const t = i18next.getFixedT(null, 'ns0', 'deep0');
t('key0');
}

export function anyJSFunction2() {
const t = i18next.getFixedT(null, 'ns1', 'deep1.deep2');

t('key1');
}

export function anyJSFunction3() {
const t = i18next.getFixedT(null, 'ns2', 'deep3.deep4');

t('key2.key3');
}
9 changes: 9 additions & 0 deletions tests/__fixtures__/testGetFixedTFunction/keyPrefix.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"description": "test keyPrefix usage of getFixedT TFunction",
"pluginOptions": {},
"expectValues": [
[{"deep0": { "key0": "" }}, {"ns": "ns0"}],
[{"deep1": { "deep2": { "key1": "" }}}, {"ns": "ns1"}],
[{"deep3": { "deep4": { "key2": { "key3": "" } }}}, {"ns": "ns2"}]
]
}
26 changes: 26 additions & 0 deletions tests/__fixtures__/testUseTranslationHook/keyPrefix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useTranslation } from 'react-i18next';

export function MyComponent1() {
const [t] = useTranslation('ns0', { keyPrefix: 'deep0' });
return <p>{t('key0')}{t('key1')}</p>
}

export function MyComponent2() {
const [t] = useTranslation('ns1', { keyPrefix: 'deep1.deep2' });
return <p>{t('key2')}{t('key3')}</p>
}

export function MyComponent3() {
const [t] = useTranslation('ns2', { keyPrefix: 'deep3.deep4' });
return <p>{t('key4.key5')}{t('key4.key6')}</p>
}

export function MyComponent4() {
const [t] = useTranslation('ns3', { keyPrefix: 'deep5.deep6' });
return <p>{t('key7.key8')}{t('key9.key10')}</p>
}

export function MyComponent5() {
const [t] = useTranslation('ns4', { keyPrefix: 'deep7.deep8' });
return <p>{t('ns5:key11')}</p>
}
11 changes: 11 additions & 0 deletions tests/__fixtures__/testUseTranslationHook/keyPrefix.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"description": "test keyPrefix extraction of useTranslation hook",
"pluginOptions": {},
"expectValues": [
[{ "deep0": {"key0": "", "key1": ""}}, {"ns": "ns0"}],
[{ "deep1": {"deep2": {"key2": "", "key3": ""}}}, {"ns": "ns1"}],
[{ "deep3": {"deep4": {"key4": { "key5": "", "key6": "" }}}}, {"ns": "ns2"}],
[{ "deep5": {"deep6": {"key7": { "key8": "" }, "key9": {"key10": ""}}}}, {"ns": "ns3"}],
[{ "key11": ""}, {"ns": "deep7.deep8.ns5"}]
]
}
9 changes: 7 additions & 2 deletions tests/__fixtures__/testUseTranslationHook/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@ const MyComponent2 = () => {
return <p>{t('key2')}</p>
}

export function MyComponent3() {
const MyComponent3 = () => {
const { t, i18n } = useTranslation();
return <p>{t('key3.key4')}</p>
}

export function MyComponent4() {
const {i18n} = useTranslation();
return <p>Shouldn't crash</p>
}

export function MyComponent4() {
export function MyComponent5() {
const { t } = ReactI18Next.useTranslation();
t('from wildcard import');
}
1 change: 1 addition & 0 deletions tests/__fixtures__/testUseTranslationHook/simple.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"key0": "",
"key1": "",
"key2": "",
"key3": { "key4": "" },
"from wildcard import": ""
}
}
1 change: 1 addition & 0 deletions tests/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export function createTranslationKey(
parsedOptions: {
contexts: false,
hasCount: false,
keyPrefix: null,
ns: null,
defaultValue: null,
},
Expand Down

0 comments on commit 8b303a6

Please sign in to comment.