Skip to content

Commit

Permalink
Merge pull request #278 from masnormen/feat/aliased-t-function
Browse files Browse the repository at this point in the history
feat: support aliased `t` functions from useTranslation hooks
  • Loading branch information
gilbsgilbs authored Dec 7, 2024
2 parents 7cc5b80 + 5f47b46 commit 6ad571b
Show file tree
Hide file tree
Showing 12 changed files with 135 additions and 5 deletions.
44 changes: 44 additions & 0 deletions src/extractors/commons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,3 +298,47 @@ export function isCustomImportedNode(
return referencesImport(name, sourceModule, importName);
});
}

/**
* Find the aliased t function name (after being destructured).
* If the destructure `t` function is not aliased, will return the identifier name as it is.
*
* For instance, given the following code:
* const { t: tCommon } = useTranslation('common');
* return <p>{tCommon('key1')}<p>
*
* // or with pluginOptions.tFunctionNames = ["myT"]
* const { myT: tCommon } = useTranslation('common');
* return <p>{tCommon('key1')}<p>
*
* getAliasedTBindingName(nodePath) should return 'tCommon' instead of t or myT
*
* @param nodePath: node path to resolve
* @param tFunctionNames: possible names for the (unaliased) t function
* @return the resolved t binding name, returning the alias if needed
*/
export function getAliasedTBindingName(
path: BabelCore.NodePath,
tFunctionNames: string[],
): string | undefined {
const properties = path.get('properties');
const propertiesArray = Array.isArray(properties)
? properties
: [properties];

for (const property of propertiesArray) {
if (property.isObjectProperty()) {
const key = property.node.key;
const value = property.node.value;
if (
key.type === 'Identifier' &&
value.type === 'Identifier' &&
tFunctionNames.includes(key.name)
) {
return value.name;
}
}
}

return tFunctionNames.find((name) => path.scope.bindings[name]);
}
6 changes: 5 additions & 1 deletion src/extractors/useTranslationHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
getFirstOrNull,
evaluateIfConfident,
referencesImport,
getAliasedTBindingName,
} from './commons';
import extractTFunction from './tFunction';

Expand Down Expand Up @@ -56,7 +57,10 @@ export default function extractUseTranslationHook(

const id = parentPath.get('id');

const tBinding = id.scope.bindings['t'];
const tBindingName = getAliasedTBindingName(id, config.tFunctionNames);
if (!tBindingName) return [];

const tBinding = id.scope.bindings[tBindingName];
if (!tBinding) return [];

let keyPrefix: string | null = null;
Expand Down
32 changes: 32 additions & 0 deletions tests/__fixtures__/testCustomHook/customNames.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useMyTranslation, useOtherTranslation } from './i18n';
import { useThirdPartyTranslation } from 'third-party-module';
import * as I18Next from 'third-party-module'

export function MyComponent0() {
const [_] = useMyTranslation('ns0');
return <p>{_('key0')}{_('key1')}</p>
}

export function MyComponent1() {
const [iceT] = useOtherTranslation(['ns1', 'noob']);
return <p>{iceT('key in ns1')}</p>
}

export function MyComponent2() {
const { translate } = I18Next.useThirdPartyTranslation('ns2');
someFunc(translate);
return <p>{translate('key in ns2')}</p>
}

export function MyComponent3() {
const foo = 'noob';
// i18next-extract-mark-ns-next-line ns3
const [myT] = useThirdPartyTranslation(foo);
return <p>{myT('key in ns3')}</p>
}

export function MyComponent4() {
const { translate: aliasedTranslate } = I18Next.useThirdPartyTranslation('ns4');
someFunc(aliasedTranslate);
return <p>{aliasedTranslate('key in ns4')}</p>
}
18 changes: 18 additions & 0 deletions tests/__fixtures__/testCustomHook/customNames.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"description": "test custom useTranslation hooks giving custom instance name to t function",
"pluginOptions": {
"customUseTranslationHooks": [
["./tests/__fixtures__/testCustomHook/i18n", "useMyTranslation"],
["./tests/__fixtures__/testCustomHook/i18n", "useOtherTranslation"],
["third-party-module", "useThirdPartyTranslation"]
],
"tFunctionNames": ["_", "iceT", "myT", "translate"]
},
"expectValues": [
[{ "key0": "", "key1": "" }, { "ns": "ns0" }],
[{ "key in ns1": "" }, { "ns": "ns1" }],
[{ "key in ns2": "" }, { "ns": "ns2" }],
[{ "key in ns3": "" }, { "ns": "ns3" }],
[{ "key in ns4": "" }, { "ns": "ns4" }]
]
}
6 changes: 6 additions & 0 deletions tests/__fixtures__/testCustomHook/namespace.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ export function MyComponent3() {
const [t] = useThirdPartyTranslation(foo);
return <p>{t('key in ns3')}</p>
}

export function MyComponent4() {
const { t: aliasedT } = I18Next.useThirdPartyTranslation('ns4');
someFunc(t);
return <p>{aliasedT('key in ns4')}</p>
}
3 changes: 2 additions & 1 deletion tests/__fixtures__/testCustomHook/namespace.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
[{"key0": "", "key1": ""}, {"ns": "ns0"}],
[{"key in ns1": ""}, {"ns": "ns1"}],
[{"key in ns2": ""}, {"ns": "ns2"}],
[{"key in ns3": ""}, {"ns": "ns3"}]
[{"key in ns3": ""}, {"ns": "ns3"}],
[{"key in ns4": ""}, {"ns": "ns4"}]
]
}
6 changes: 6 additions & 0 deletions tests/__fixtures__/testUseTranslationHook/keyPrefix.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ export function MyComponent5() {
const [t] = useTranslation('ns4', { keyPrefix: 'deep7.deep8' });
return <p>{t('ns5:key11')}</p>
}

export function MyComponent6() {
const { t: aliasedT } = useTranslation('ns6', { keyPrefix: 'deep1.deep2' });
return <p>{aliasedT('key12')}</p>
}

3 changes: 2 additions & 1 deletion tests/__fixtures__/testUseTranslationHook/keyPrefix.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
[{ "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"}]
[{ "key11": ""}, {"ns": "deep7.deep8.ns5"}],
[{ "deep1": {"deep2": {"key12": ""}}}, {"ns": "ns6"}]
]
}
5 changes: 5 additions & 0 deletions tests/__fixtures__/testUseTranslationHook/namespace.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,8 @@ export function MyComponent4() {
someFunc(t);
return <p>{t('key0')}</p>
}

export function MyComponent5() {
const { t: aliasedT } = useTranslation('ns4');
return <p>{aliasedT('key0')}</p>
}
3 changes: 2 additions & 1 deletion tests/__fixtures__/testUseTranslationHook/namespace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[{"key0": "", "key1": ""}, {"ns": "ns0"}],
[{"key0": ""}, {"ns": "ns1"}],
[{"key0": ""}, {"ns": "ns2"}],
[{"key0": ""}, {"ns": "ns3"}]
[{"key0": ""}, {"ns": "ns3"}],
[{"key0": ""}, {"ns": "ns4"}]
]
}
10 changes: 10 additions & 0 deletions tests/__fixtures__/testUseTranslationHook/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,13 @@ export function MyComponent5() {
const { t } = ReactI18Next.useTranslation();
t('from wildcard import');
}

export function MyComponent6() {
const { t: aliasedT } = ReactI18Next.useTranslation();
aliasedT('from wildcard import but aliased');
}

export const MyComponent7 = () => {
const { t: aliasedT } = useTranslation();
return <p>{aliasedT('key5')}</p>
}
4 changes: 3 additions & 1 deletion tests/__fixtures__/testUseTranslationHook/simple.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"key1": "",
"key2": "",
"key3": { "key4": "" },
"from wildcard import": ""
"from wildcard import": "",
"from wildcard import but aliased": "",
"key5": ""
}
}

0 comments on commit 6ad571b

Please sign in to comment.