Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type-safe translations do not work with plurals #1386

Closed
Mephistofeles opened this issue Oct 6, 2021 · 10 comments · Fixed by #1399
Closed

Type-safe translations do not work with plurals #1386

Mephistofeles opened this issue Oct 6, 2021 · 10 comments · Fixed by #1399
Assignees

Comments

@Mephistofeles
Copy link

🐛 Bug Report

After setting up TypeScript type definitions I cannot use plurals support:

To Reproduce

{
  "key_one": "item",
  "key_other": "items",
}

t('key', {count: 0}); // TS error, only key_one or key_other are allowed
t('key', {count: 1}); // TS error

Expected behavior

Such resources should be allowed to be used without the suffix.

Your Environment

  • react-i18next@11.12.0
@adrai
Copy link
Member

adrai commented Oct 6, 2021

Was this supported with i18next json format v3 in TypeScript?
Need @pedrodurek's help...

@Mephistofeles
Copy link
Author

I haven't used v3, but it should work, as singular value has no suffix:

{
  "keyPluralSimple": "the singular",
  "keyPluralSimple_plural": "the plural"
}

@pedrodurek
Copy link
Member

I don't think we support plurals for t function, just for Trans, Plural, SelectOrdinal and Select components. I'll see what we can do https://github.com/i18next/react-i18next/blob/master/ts4.1/icu.macro.d.ts

@stale
Copy link

stale bot commented Oct 14, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the stale label Oct 14, 2021
@jer-sen
Copy link

jer-sen commented Oct 19, 2021

@pedrodurek @adrai types in ts4.1/index.d.ts must be updated to support new json format v4.
Here is something working for me:

@@ -34,14 +34,15 @@ export interface Resources {}
  * import 'react-i18next';
  * declare module 'react-i18next' {
  *   interface CustomTypeOptions {
- *     defaultNS: 'custom';
+ *     defaultNS: 'custom',
  *     returnNull: false,
  *     returnEmptyString: false,
  *     resources: {
  *       custom: {
- *         foo: 'foo';
- *       };
- *     };
+ *         foo: 'foo',
+ *       },
+ *     },
+ *     jsonFormat: 'v4',
  *   }
  * }
  * ```
@@ -56,6 +57,7 @@ type TypeOptions = MergeBy<
     returnEmptyString: true;
     defaultNS: 'translation';
     resources: Resources;
+    jsonFormat: 'v4',
   },
   CustomTypeOptions
 >;
@@ -92,16 +94,24 @@ declare module 'i18next' {
 }
 
 // Normalize single namespace
+type WithOrWithoutPlural<K> =
+  TypeOptions['jsonFormat'] extends 'v4' ?
+    K extends unknown ?
+      K extends `${infer B}_${'zero' | 'one' | 'two' | 'few' | 'many' | 'other'}` ? B | K : K
+      : never
+    :
+    K
+;
 type AppendKeys<K1, K2> = `${K1 & string}.${K2 & string}`;
 type AppendKeys2<K1, K2> = `${K1 & string}.${Exclude<K2, keyof any[]> & string}`;
 type Normalize2<T, K = keyof T> = K extends keyof T
   ? T[K] extends Record<string, any>
     ? T[K] extends readonly any[]
-      ? AppendKeys2<K, keyof T[K]> | AppendKeys2<K, Normalize2<T[K]>>
-      : AppendKeys<K, keyof T[K]> | AppendKeys<K, Normalize2<T[K]>>
+      ? AppendKeys2<K, WithOrWithoutPlural<keyof T[K]>> | AppendKeys2<K, Normalize2<T[K]>>
+      : AppendKeys<K, WithOrWithoutPlural<keyof T[K]>> | AppendKeys<K, Normalize2<T[K]>>
     : never
   : never;
-type Normalize<T> = keyof T | Normalize2<T>;
+type Normalize<T> = WithOrWithoutPlural<keyof T> | Normalize2<T>;
 
 // Normalize multiple namespaces
 type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void

@stale stale bot removed the stale label Oct 19, 2021
@njacob1001
Copy link

@pedrodurek @adrai types in ts4.1/index.d.ts must be updated to support new json format v4. Here is something working for me:

@@ -34,14 +34,15 @@ export interface Resources {}
  * import 'react-i18next';
  * declare module 'react-i18next' {
  *   interface CustomTypeOptions {
- *     defaultNS: 'custom';
+ *     defaultNS: 'custom',
  *     returnNull: false,
  *     returnEmptyString: false,
  *     resources: {
  *       custom: {
- *         foo: 'foo';
- *       };
- *     };
+ *         foo: 'foo',
+ *       },
+ *     },
+ *     jsonFormat: 'v4',
  *   }
  * }
  * ```
@@ -56,6 +57,7 @@ type TypeOptions = MergeBy<
     returnEmptyString: true;
     defaultNS: 'translation';
     resources: Resources;
+    jsonFormat: 'v4',
   },
   CustomTypeOptions
 >;
@@ -92,16 +94,24 @@ declare module 'i18next' {
 }
 
 // Normalize single namespace
+type WithOrWithoutPlural<K> =
+  TypeOptions['jsonFormat'] extends 'v4' ?
+    K extends unknown ?
+      K extends `${infer B}_${'zero' | 'one' | 'two' | 'few' | 'many' | 'other'}` ? B | K : K
+      : never
+    :
+    K
+;
 type AppendKeys<K1, K2> = `${K1 & string}.${K2 & string}`;
 type AppendKeys2<K1, K2> = `${K1 & string}.${Exclude<K2, keyof any[]> & string}`;
 type Normalize2<T, K = keyof T> = K extends keyof T
   ? T[K] extends Record<string, any>
     ? T[K] extends readonly any[]
-      ? AppendKeys2<K, keyof T[K]> | AppendKeys2<K, Normalize2<T[K]>>
-      : AppendKeys<K, keyof T[K]> | AppendKeys<K, Normalize2<T[K]>>
+      ? AppendKeys2<K, WithOrWithoutPlural<keyof T[K]>> | AppendKeys2<K, Normalize2<T[K]>>
+      : AppendKeys<K, WithOrWithoutPlural<keyof T[K]>> | AppendKeys<K, Normalize2<T[K]>>
     : never
   : never;
-type Normalize<T> = keyof T | Normalize2<T>;
+type Normalize<T> = WithOrWithoutPlural<keyof T> | Normalize2<T>;
 
 // Normalize multiple namespaces
 type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void

how can I put that in a react app?

@jer-sen
Copy link

jer-sen commented Oct 19, 2021

@njacob1001 you can use patch-package module

@pedrodurek
Copy link
Member

I'll look into it, PR is welcome as well

@stale
Copy link

stale bot commented Oct 26, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale
Copy link

stale bot commented Nov 3, 2021

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants