Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: i18next/react-i18next
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v14.0.0
Choose a base ref
...
head repository: i18next/react-i18next
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v14.0.1
Choose a head ref

Commits on Dec 23, 2023

  1. Copy the full SHA
    84270f7 View commit details

Commits on Dec 28, 2023

  1. Copy the full SHA
    44ab5f3 View commit details

Commits on Jan 2, 2024

  1. test: migrate ts test to vitest (#1707)

    * chore(prettierrc): add schema and replace `jsxBracketSameLine` with `bracketSameLine`
    
    * test: migrate ts test to `vitest`
    marcalexiei authored Jan 2, 2024
    Copy the full SHA
    0aabd04 View commit details
  2. Copy the full SHA
    4b8e0fd View commit details
  3. year

    adrai committed Jan 2, 2024
    Copy the full SHA
    a23773d View commit details
  4. test: migrate to vitest (#1708)

    * test: migrate to vitest
    
    * refactor(TransWithoutContext): use React function to create JSX element
    
    * update i18next to 23.7.13
    marcalexiei authored Jan 2, 2024
    Copy the full SHA
    63ad0a9 View commit details
  5. vitest run

    adrai committed Jan 2, 2024
    Copy the full SHA
    7a40ea0 View commit details
  6. try without coverage

    adrai committed Jan 2, 2024
    Copy the full SHA
    5692e5b View commit details
  7. Copy the full SHA
    21e7738 View commit details
  8. update deps

    adrai committed Jan 2, 2024
    Copy the full SHA
    e45fbcd View commit details
  9. Copy the full SHA
    5bcbee4 View commit details

Commits on Jan 3, 2024

  1. missing files for example

    adrai committed Jan 3, 2024
    Copy the full SHA
    2acc040 View commit details
  2. Copy the full SHA
    8be0c29 View commit details

Commits on Jan 4, 2024

  1. github action

    adrai committed Jan 4, 2024
    Copy the full SHA
    f5d2761 View commit details
  2. Copy the full SHA
    cdc35ca View commit details
  3. bye circleci

    adrai committed Jan 4, 2024
    Copy the full SHA
    a054a76 View commit details
  4. Copy the full SHA
    0ef387c View commit details
  5. rename github action workflow

    adrai committed Jan 4, 2024
    Copy the full SHA
    048493c View commit details
  6. fix link in readme

    adrai committed Jan 4, 2024
    Copy the full SHA
    06d29ca View commit details
  7. fix link in readme

    adrai committed Jan 4, 2024
    Copy the full SHA
    a62a75f View commit details
  8. rename github action workflow

    adrai committed Jan 4, 2024
    Copy the full SHA
    04a8e0c View commit details
  9. try coveralls step

    adrai committed Jan 4, 2024
    Copy the full SHA
    a8be568 View commit details
  10. Copy the full SHA
    2d0424d View commit details
  11. lint is in pretest

    adrai committed Jan 4, 2024
    Copy the full SHA
    26f83a8 View commit details

Commits on Jan 20, 2024

  1. Copy the full SHA
    c58ba2a View commit details
  2. release

    adrai committed Jan 20, 2024
    Copy the full SHA
    c14d4e4 View commit details
  3. build

    adrai committed Jan 20, 2024
    Copy the full SHA
    1df77dd View commit details
  4. 14.0.1

    adrai committed Jan 20, 2024
    Copy the full SHA
    0321c04 View commit details
Showing with 30,138 additions and 31,335 deletions.
  1. +0 −22 .circleci/config.yml
  2. +5 −1 .codeclimate.yml
  3. +19 −15 .eslintrc → .eslintrc.json
  4. +38 −0 .github/workflows/lint_and_test.yml
  5. +3 −0 .gitignore
  6. +3 −3 .npmignore
  7. +2 −1 .prettierrc → .prettierrc.json
  8. +4 −0 CHANGELOG.md
  9. +1 −1 LICENSE
  10. +1 −1 README.md
  11. +4 −3 example/ReactNativeLocizeProject/App.tsx
  12. +2 −1 example/ReactNativeLocizeProject/Gemfile
  13. +15 −14 example/ReactNativeLocizeProject/Gemfile.lock
  14. +1 −1 example/ReactNativeLocizeProject/__tests__/App.test.tsx
  15. +4 −8 example/ReactNativeLocizeProject/android/app/build.gradle
  16. +1 −5 example/ReactNativeLocizeProject/android/app/src/debug/AndroidManifest.xml
  17. +0 −75 ...tiveLocizeProject/android/app/src/debug/java/com/reactnativelocizeproject/ReactNativeFlipper.java
  18. +0 −32 ...ReactNativeLocizeProject/android/app/src/main/java/com/reactnativelocizeproject/MainActivity.java
  19. +22 −0 ...e/ReactNativeLocizeProject/android/app/src/main/java/com/reactnativelocizeproject/MainActivity.kt
  20. +0 −62 ...ctNativeLocizeProject/android/app/src/main/java/com/reactnativelocizeproject/MainApplication.java
  21. +45 −0 ...eactNativeLocizeProject/android/app/src/main/java/com/reactnativelocizeproject/MainApplication.kt
  22. +0 −20 ...veLocizeProject/android/app/src/release/java/com/reactnativelocizeproject/ReactNativeFlipper.java
  23. +8 −8 example/ReactNativeLocizeProject/android/build.gradle
  24. +0 −3 example/ReactNativeLocizeProject/android/gradle.properties
  25. BIN example/ReactNativeLocizeProject/android/gradle/wrapper/gradle-wrapper.jar
  26. +2 −1 example/ReactNativeLocizeProject/android/gradle/wrapper/gradle-wrapper.properties
  27. +12 −7 example/ReactNativeLocizeProject/android/gradlew
  28. +1 −1 example/ReactNativeLocizeProject/babel.config.js
  29. +0 −8 example/ReactNativeLocizeProject/ios/Podfile
  30. +942 −289 example/ReactNativeLocizeProject/ios/Podfile.lock
  31. +20 −26 example/ReactNativeLocizeProject/ios/ReactNativeLocizeProject.xcodeproj/project.pbxproj
  32. +0 −8 .../ios/ReactNativeLocizeProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
  33. +5 −0 example/ReactNativeLocizeProject/ios/ReactNativeLocizeProject/AppDelegate.mm
  34. +4 −8 example/ReactNativeLocizeProject/ios/ReactNativeLocizeProject/Info.plist
  35. +6,190 −5,112 example/ReactNativeLocizeProject/package-lock.json
  36. +17 −17 example/ReactNativeLocizeProject/package.json
  37. +1 −1 example/ReactNativeLocizeProject/tsconfig.json
  38. +52 −44 example/ReactNativeProject/App.tsx
  39. +2 −1 example/ReactNativeProject/Gemfile
  40. +15 −14 example/ReactNativeProject/Gemfile.lock
  41. +1 −1 example/ReactNativeProject/__tests__/App.test.tsx
  42. +4 −8 example/ReactNativeProject/android/app/build.gradle
  43. +1 −5 example/ReactNativeProject/android/app/src/debug/AndroidManifest.xml
  44. +0 −75 example/ReactNativeProject/android/app/src/debug/java/com/reactnativeproject/ReactNativeFlipper.java
  45. +0 −32 example/ReactNativeProject/android/app/src/main/java/com/reactnativeproject/MainActivity.java
  46. +22 −0 example/ReactNativeProject/android/app/src/main/java/com/reactnativeproject/MainActivity.kt
  47. +0 −62 example/ReactNativeProject/android/app/src/main/java/com/reactnativeproject/MainApplication.java
  48. +45 −0 example/ReactNativeProject/android/app/src/main/java/com/reactnativeproject/MainApplication.kt
  49. +0 −20 ...le/ReactNativeProject/android/app/src/release/java/com/reactnativeproject/ReactNativeFlipper.java
  50. +8 −8 example/ReactNativeProject/android/build.gradle
  51. +0 −3 example/ReactNativeProject/android/gradle.properties
  52. BIN example/ReactNativeProject/android/gradle/wrapper/gradle-wrapper.jar
  53. +2 −1 example/ReactNativeProject/android/gradle/wrapper/gradle-wrapper.properties
  54. +12 −7 example/ReactNativeProject/android/gradlew
  55. +1 −1 example/ReactNativeProject/babel.config.js
  56. +24 −0 example/ReactNativeProject/i18n.js
  57. +3 −0 example/ReactNativeProject/index.js
  58. +0 −7 example/ReactNativeProject/ios/Podfile
  59. +943 −284 example/ReactNativeProject/ios/Podfile.lock
  60. +20 −26 example/ReactNativeProject/ios/ReactNativeProject.xcodeproj/project.pbxproj
  61. +5 −0 example/ReactNativeProject/ios/ReactNativeProject/AppDelegate.mm
  62. +4 −8 example/ReactNativeProject/ios/ReactNativeProject/Info.plist
  63. +10 −0 example/ReactNativeProject/locales/de/translation.json
  64. +10 −0 example/ReactNativeProject/locales/en/translation.json
  65. +6,129 −5,032 example/ReactNativeProject/package-lock.json
  66. +14 −13 example/ReactNativeProject/package.json
  67. +1 −1 example/ReactNativeProject/tsconfig.json
  68. +1 −1 index.d.ts
  69. +13,231 −17,853 package-lock.json
  70. +12 −41 package.json
  71. +830 −846 react-i18next.js
  72. +1 −1 react-i18next.min.js
  73. +16 −4 src/TransWithoutContext.js
  74. +0 −12 test/.eslintrc
  75. +9 −0 test/.eslintrc.json
  76. +8 −3 test/{I18nextProvider.spec.js → I18nextProvider.spec.jsx}
  77. +7 −2 test/{Translation.spec.js → Translation.spec.jsx}
  78. +115 −115 test/__snapshots__/icu.macro.spec.js.snap
  79. +3 −3 test/{lngAwareBackendMock.js → backendLngAwareMock.js}
  80. +1 −3 test/backendMock.js
  81. +12 −0 test/icu.macro.spec.js
  82. +4 −1 test/setup.js
  83. +2 −1 test/{trans.nodeToString.spec.js → trans.nodeToString.spec.jsx}
  84. +11 −1 test/{trans.render.dynamic.spec.js → trans.render.dynamic.spec.jsx}
  85. +6 −1 test/{trans.render.icu.spec.js → trans.render.icu.spec.jsx}
  86. +6 −1 test/{trans.render.object.spec.js → trans.render.object.spec.jsx}
  87. +6 −1 test/{trans.render.spec.js → trans.render.spec.jsx}
  88. +0 −41 test/typescript/I18nextProvider.test.tsx
  89. +0 −107 test/typescript/Trans.test.tsx
  90. +0 −99 test/typescript/TransWithoutContext.test.tsx
  91. +0 −24 test/typescript/Translation.test.tsx
  92. +0 −10 test/typescript/context.test.tsx
  93. +117 −114 test/typescript/custom-types/Trans.test.tsx
  94. +104 −81 test/typescript/custom-types/TransWithoutContext.test.tsx
  95. +41 −0 test/typescript/custom-types/Translation.test.ts
  96. +0 −42 test/typescript/custom-types/Translation.test.tsx
  97. +2 −0 test/typescript/custom-types/{custom-types.d.ts → i18next.d.ts}
  98. +111 −0 test/typescript/custom-types/useTranslation.test.ts
  99. +0 −100 test/typescript/custom-types/useTranslation.test.tsx
  100. +0 −78 test/typescript/examples.test.tsx
  101. +0 −71 test/typescript/i18n.ts
  102. +20 −0 test/typescript/misc/I18nextProvider.test.tsx
  103. +132 −0 test/typescript/misc/Trans.test.tsx
  104. +96 −0 test/typescript/misc/TransWithoutContext.test.tsx
  105. +41 −0 test/typescript/misc/Translation.test.tsx
  106. +8 −0 test/typescript/misc/context.test.tsx
  107. +5 −0 test/typescript/misc/tsconfig.json
  108. 0 { → test/typescript/misc}/tsconfig.nonEsModuleInterop.json
  109. +10 −0 test/typescript/misc/useSSR.test.tsx
  110. +81 −0 test/typescript/misc/useTranslation.test.ts
  111. +71 −0 test/typescript/misc/withSSR.test.tsx
  112. +97 −0 test/typescript/misc/withTranslation.test.tsx
  113. +0 −18 test/typescript/useSSR.test.tsx
  114. +0 −27 test/typescript/useTranslation.test.tsx
  115. +0 −46 test/typescript/withSSR.test.tsx
  116. +0 −82 test/typescript/withTranslation.test.tsx
  117. +34 −5 test/unescape.spec.js
  118. +2 −1 test/useSSR.spec.js
  119. +3 −2 test/useTranslation.loading.spec.js
  120. +37 −28 test/useTranslation.loadingLng.spec.js
  121. +10 −4 test/{useTranslation.ready.spec.js → useTranslation.ready.spec.jsx}
  122. +9 −4 test/{useTranslation.spec.js → useTranslation.spec.jsx}
  123. +7 −2 test/useTranslation.usedNamespaces.spec.js
  124. +33 −27 test/{withSSR.spec.js → withSSR.spec.jsx}
  125. +7 −2 test/{withTranslation.keyPrefix.spec.js → withTranslation.keyPrefix.spec.jsx}
  126. +7 −2 test/{withTranslation.spec.js → withTranslation.spec.jsx}
  127. +3 −4 tsconfig.json
  128. +0 −17 tslint.json
  129. +17 −0 vitest.config.mts
  130. +52 −0 vitest.workspace.mts
22 changes: 0 additions & 22 deletions .circleci/config.yml

This file was deleted.

6 changes: 5 additions & 1 deletion .codeclimate.yml
Original file line number Diff line number Diff line change
@@ -9,7 +9,11 @@ engines:
- python
- php
eslint:
enabled: true
# Disabled since this engine used a different set of version of
# `@typescript/eslint` and `typescript`
#
# @see https://github.com/i18next/i18next/pull/2098
enabled: false
channel: "eslint-8"
fixme:
enabled: true
34 changes: 19 additions & 15 deletions .eslintrc → .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{
"extends": [
"airbnb",
"prettier"
],
"extends": ["airbnb", "prettier"],
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 8,
@@ -14,8 +11,7 @@
},
"env": {
"browser": true,
"node": true,
"jquery": true
"node": true
},
"rules": {
"no-debugger": 0,
@@ -27,9 +23,11 @@
}
],
"prefer-arrow-callback": [
"error", {
"allowNamedFunctions": true
}],
"error",
{
"allowNamedFunctions": true
}
],
"prefer-const": [
"error",
{
@@ -65,9 +63,12 @@
"consistent-return": 0,
"react/display-name": 1,
"react/no-array-index-key": 0,
"react/jsx-no-useless-fragment": ["error", {
"allowExpressions": true
}],
"react/jsx-no-useless-fragment": [
"error",
{
"allowExpressions": true
}
],
"react/react-in-jsx-scope": 0,
"react/prefer-stateless-function": 0,
"react/forbid-prop-types": 0,
@@ -80,9 +81,12 @@
"extensions": [".js", ".jsx"]
}
],
"react/no-unknown-property": ["error", {
"ignore": ["i18nIsDynamicList"]
}],
"react/no-unknown-property": [
"error",
{
"ignore": ["i18nIsDynamicList"]
}
],
"radix": 0,
"no-shadow": [
2,
38 changes: 38 additions & 0 deletions .github/workflows/lint_and_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Lint & Test

on:
push:
branches:
- master
pull_request:
# types: [opened, synchronize, reopened, ready_for_review]
branches:
- '**'

jobs:
test:
name: Lint & test on node ${{ matrix.node }} and ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
node: [ '20.x', '18.x' ]
# os: [ubuntu-latest, windows-latest, macOS-latest]
os: [ubuntu-latest]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Install dependencies
run: npm install
# lint is included in pretest
# - name: Lint
# run: npm run lint
- name: Test
run: npm test
- name: Coverage
run: npm run test:coverage
# run: npm run test:coverage && cat ./coverage/lcov.info | node_modules/.bin/coveralls --verbose
- name: Coveralls
uses: coverallsapp/github-action@v2
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -27,3 +27,6 @@ out

# ignore packaged releases
*.tgz

# vitest temp / cache files
tsconfig.vitest-temp.json
6 changes: 3 additions & 3 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -8,8 +8,6 @@ bin/
.eslintrc
.gitignore
bower.json
gulpfile.js
karma.conf.js
.github
.circleci
.vscode
@@ -19,4 +17,6 @@ rollup.config.mjs
.codeclimate.yml
.coveralls.yml
tsconfig*.json
.prettierrc
.prettierrc.json
vitest.config.mts
vitest.workspace.mts
3 changes: 2 additions & 1 deletion .prettierrc → .prettierrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"$schema": "https://json.schemastore.org/prettierrc.json",
"bracketSpacing": true,
"jsxBracketSameLine": false,
"bracketSameLine": false,
"printWidth": 100,
"semi": true,
"singleQuote": true,
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### 14.0.1

- types: fix typo in `CustomInstanceExtensions` [1713](https://github.com/i18next/react-i18next/pull/1713)

### 14.0.0

- types: reportNamespaces is now optional, should fix [1693](https://github.com/i18next/react-i18next/issues/1693)
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2023 i18next
Copyright (c) 2024 i18next

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# react-i18next [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Awesome%20react-i18next%20for%20react.js%20based%20on%20i18next%20internationalization%20ecosystem%20&url=https://github.com/i18next/react-i18next&via=jamuhl&hashtags=i18n,reactjs,js,dev)

[![CircleCI](https://circleci.com/gh/i18next/react-i18next.svg?style=svg)](https://circleci.com/gh/i18next/react-i18next)
[![Lint & Test](https://github.com/i18next/react-i18next/actions/workflows/lint_and_test.yml/badge.svg)](https://github.com/i18next/react-i18next/actions/workflows/lint_and_test.yml)
[![Code Climate](https://codeclimate.com/github/codeclimate/codeclimate/badges/gpa.svg)](https://codeclimate.com/github/i18next/react-i18next)
[![Coverage Status](https://coveralls.io/repos/github/i18next/react-i18next/badge.svg)](https://coveralls.io/github/i18next/react-i18next)
[![Quality][quality-badge]][quality-url]
7 changes: 4 additions & 3 deletions example/ReactNativeLocizeProject/App.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {Suspense, Component} from 'react';
import {Text, Button, View, TouchableOpacity} from 'react-native';
import {Text, Button, View} from 'react-native';
import {useTranslation, withTranslation, Trans} from 'react-i18next';
import type {TFunction} from 'i18next';

// use hoc for class based components
class LegacyWelcomeClass extends Component {
class LegacyWelcomeClass extends Component<{t: TFunction}> {
render() {
const {t} = this.props;
return <Text>{t('title')}</Text>;
@@ -25,7 +26,7 @@ function MyComponent() {
function AppInner() {
const {t, i18n} = useTranslation();

const changeLanguage = lng => {
const changeLanguage = (lng: string) => {
i18n.changeLanguage(lng);
};

3 changes: 2 additions & 1 deletion example/ReactNativeLocizeProject/Gemfile
Original file line number Diff line number Diff line change
@@ -3,4 +3,5 @@ source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby ">= 2.6.10"

gem 'cocoapods', '~> 1.12'
gem 'cocoapods', '~> 1.13'
gem 'activesupport', '>= 6.1.7.3', '< 7.1.0'
29 changes: 15 additions & 14 deletions example/ReactNativeLocizeProject/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -9,19 +9,19 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.5)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
claide (1.1.0)
cocoapods (1.12.1)
cocoapods (1.14.3)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.12.1)
cocoapods-core (= 1.14.3)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.6.0, < 2.0)
cocoapods-downloader (>= 2.1, < 3.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.6.0, < 2.0)
@@ -33,8 +33,8 @@ GEM
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.12.1)
xcodeproj (>= 1.23.0, < 2.0)
cocoapods-core (1.14.3)
activesupport (>= 5.0, < 8)
addressable (~> 2.8)
algoliasearch (~> 1.0)
@@ -45,7 +45,7 @@ GEM
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.6.3)
cocoapods-downloader (2.1)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
@@ -58,40 +58,41 @@ GEM
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
ffi (1.15.5)
ffi (1.16.3)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
httpclient (2.8.3)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
json (2.6.3)
minitest (5.19.0)
json (2.7.1)
minitest (5.20.0)
molinillo (0.8.0)
nanaimo (0.3.0)
nap (1.1.0)
netrc (0.11.0)
public_suffix (4.0.7)
rexml (3.2.6)
ruby-macho (2.5.1)
typhoeus (1.4.0)
typhoeus (1.4.1)
ethon (>= 0.9.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
xcodeproj (1.22.0)
xcodeproj (1.23.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
zeitwerk (2.6.11)
zeitwerk (2.6.12)

PLATFORMS
ruby

DEPENDENCIES
cocoapods (~> 1.12)
activesupport (>= 6.1.7.3, < 7.1.0)
cocoapods (~> 1.13)

RUBY VERSION
ruby 2.6.10p210
2 changes: 1 addition & 1 deletion example/ReactNativeLocizeProject/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ import 'react-native';
import React from 'react';
import App from '../App';

// Note: import explicitly to use the types shiped with jest.
// Note: import explicitly to use the types shipped with jest.
import {it} from '@jest/globals';

// Note: test renderer must be required after react-native.
12 changes: 4 additions & 8 deletions example/ReactNativeLocizeProject/android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"

/**
@@ -70,8 +71,8 @@ def jscFlavor = 'org.webkit:android-jsc:+'

android {
ndkVersion rootProject.ext.ndkVersion

compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion

namespace "com.reactnativelocizeproject"
defaultConfig {
@@ -106,13 +107,8 @@ android {
dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
implementation("com.facebook.react:flipper-integration")

debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.squareup.okhttp3', module:'okhttp'
}

debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
Original file line number Diff line number Diff line change
@@ -2,12 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<application
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
</application>
tools:ignore="GoogleAppIndexingWarning"/>
</manifest>

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.reactnativelocizeproject

import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate

class MainActivity : ReactActivity() {

/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "ReactNativeLocizeProject"

/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.reactnativelocizeproject

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.flipper.ReactNativeFlipper
import com.facebook.soloader.SoLoader

class MainApplication : Application(), ReactApplication {

override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return PackageList(this).packages
}

override fun getJSMainModuleName(): String = "index"

override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}

override val reactHost: ReactHost
get() = getDefaultReactHost(this.applicationContext, reactNativeHost)

override fun onCreate() {
super.onCreate()
SoLoader.init(this, false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager)
}
}

This file was deleted.

16 changes: 8 additions & 8 deletions example/ReactNativeLocizeProject/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext {
buildToolsVersion = "33.0.0"
buildToolsVersion = "34.0.0"
minSdkVersion = 21
compileSdkVersion = 33
targetSdkVersion = 33

// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
ndkVersion = "23.1.7779620"
compileSdkVersion = 34
targetSdkVersion = 34
ndkVersion = "25.1.8937393"
kotlinVersion = "1.8.0"
}
repositories {
google()
@@ -17,5 +14,8 @@ buildscript {
dependencies {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
}
}

apply plugin: "com.facebook.react.rootproject"
3 changes: 0 additions & 3 deletions example/ReactNativeLocizeProject/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -24,9 +24,6 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true

# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.182.0

# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
19 changes: 12 additions & 7 deletions example/ReactNativeLocizeProject/android/gradlew
Original file line number Diff line number Diff line change
@@ -83,10 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,26 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -197,6 +198,10 @@ if "$cygwin" || "$msys" ; then
done
fi


# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
2 changes: 1 addition & 1 deletion example/ReactNativeLocizeProject/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
presets: ['module:@react-native/babel-preset'],
};
8 changes: 0 additions & 8 deletions example/ReactNativeLocizeProject/ios/Podfile
Original file line number Diff line number Diff line change
@@ -28,15 +28,8 @@ end
target 'ReactNativeLocizeProject' do
config = use_native_modules!

# Flags change depending on the env values.
flags = get_default_flags()

use_react_native!(
:path => config[:reactNativePath],
# Hermes is now enabled by default. Disable by setting this flag to false.
:hermes_enabled => flags[:hermes_enabled],
# :hermes_enabled => false,
:fabric_enabled => flags[:fabric_enabled],
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
@@ -58,6 +51,5 @@ target 'ReactNativeLocizeProject' do
config[:reactNativePath],
:mac_catalyst_enabled => false
)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
end
end
1,231 changes: 942 additions & 289 deletions example/ReactNativeLocizeProject/ios/Podfile.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -177,7 +177,6 @@
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeLocizeProject" */;
buildPhases = (
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
@@ -378,25 +377,6 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeLocizeProject-ReactNativeLocizeProjectTests/Pods-ReactNativeLocizeProject-ReactNativeLocizeProjectTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Start Packager";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
@@ -438,7 +418,7 @@
"$(inherited)",
);
INFOPLIST_FILE = ReactNativeLocizeProjectTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -462,7 +442,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = ReactNativeLocizeProjectTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -536,7 +516,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -580,7 +560,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
@@ -598,9 +578,16 @@
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
};
name = Debug;
};
@@ -609,7 +596,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -646,7 +633,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
@@ -663,9 +650,16 @@
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
VALIDATE_PRODUCT = YES;
};
name = Release;

This file was deleted.

Original file line number Diff line number Diff line change
@@ -15,6 +15,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self getBundleURL];
}

- (NSURL *)getBundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
Original file line number Diff line number Diff line change
@@ -26,14 +26,10 @@
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
11,302 changes: 6,190 additions & 5,112 deletions example/ReactNativeLocizeProject/package-lock.json

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions example/ReactNativeLocizeProject/package.json
Original file line number Diff line number Diff line change
@@ -10,34 +10,34 @@
"test": "jest"
},
"dependencies": {
"@os-team/i18next-react-native-language-detector": "1.0.28",
"i18next": "23.4.6",
"i18next-chained-backend": "4.4.0",
"i18next-localstorage-backend": "4.1.1",
"i18next-locize-backend": "6.2.3",
"@os-team/i18next-react-native-language-detector": "1.0.30",
"i18next": "23.7.15",
"i18next-chained-backend": "4.6.2",
"i18next-localstorage-backend": "4.2.0",
"i18next-locize-backend": "6.4.1",
"intl-pluralrules": "2.0.1",
"react": "18.2.0",
"react-i18next": "13.2.2",
"react-native": "0.72.4"
"react-i18next": "14.0.0",
"react-native": "0.73.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
"@react-native/eslint-config": "^0.72.2",
"@react-native/metro-config": "^0.72.11",
"@tsconfig/react-native": "^3.0.0",
"@types/react": "^18.0.24",
"@react-native/babel-preset": "^0.73.18",
"@react-native/eslint-config": "^0.73.1",
"@react-native/metro-config": "^0.73.2",
"@react-native/typescript-config": "^0.73.1",
"@types/react": "^18.2.6",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.2.1",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"jest": "^29.2.1",
"metro-react-native-babel-preset": "0.76.8",
"prettier": "^2.4.1",
"jest": "^29.6.3",
"prettier": "2.8.8",
"react-test-renderer": "18.2.0",
"typescript": "4.8.4"
"typescript": "5.0.4"
},
"engines": {
"node": ">=16"
"node": ">=18"
}
}
2 changes: 1 addition & 1 deletion example/ReactNativeLocizeProject/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "@tsconfig/react-native/tsconfig.json"
"extends": "@react-native/typescript-config/tsconfig.json"
}
96 changes: 52 additions & 44 deletions example/ReactNativeProject/App.tsx
Original file line number Diff line number Diff line change
@@ -1,52 +1,60 @@
import React from 'react';
import {Text, View, TouchableOpacity} from 'react-native';
import 'intl-pluralrules';
import i18next, {LanguageDetectorAsyncModule} from 'i18next';
import {initReactI18next, useTranslation} from 'react-i18next';

const languageDetector: LanguageDetectorAsyncModule = {
type: 'languageDetector',
async: true,
detect: cb => cb('en'),
init: () => {},
cacheUserLanguage: () => {},
};

i18next
.use(languageDetector)
.use(initReactI18next)
.init({
fallbackLng: 'en',
debug: true,
resources: {
en: {
translation: {
hello: 'Hello world',
change: 'Change language',
},
},
sv: {
translation: {
hello: 'Hej världen',
change: 'Byt språk',
},
},
},
});
import {Suspense, Component} from 'react';
import {Text, Button, View} from 'react-native';
import {useTranslation, withTranslation, Trans} from 'react-i18next';
import type {TFunction} from 'i18next';

export default function App() {
// use hoc for class based components
class LegacyWelcomeClass extends Component<{t: TFunction}> {
render() {
const {t} = this.props;
return <Text>{t('title')}</Text>;
}
}
const Welcome = withTranslation()(LegacyWelcomeClass);

// Component using the Trans component
function MyComponent() {
return (
<Text>
<Trans i18nKey="description.part1">
To get started, edit <Text>src/App.js</Text> and save to reload.
</Trans>
</Text>
);
}

function AppInner() {
const {t, i18n} = useTranslation();

const changeLanguage = (lng: string) => {
i18n.changeLanguage(lng);
};

return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text style={{fontSize: 20, marginBottom: 20}}>{t('hello')}</Text>

<TouchableOpacity
onPress={() =>
i18n.changeLanguage(i18n.language === 'sv' ? 'en' : 'sv')
}>
<Text>{t('change')}</Text>
</TouchableOpacity>
<Welcome />

<Button
onPress={() => changeLanguage('en')}
title="en"
disabled={i18n.resolvedLanguage === 'en'}
/>
<Button
onPress={() => changeLanguage('de')}
title="de"
disabled={i18n.resolvedLanguage === 'de'}
/>

<MyComponent />
<Text>{t('description.part2')}</Text>
</View>
);
}

export default function App() {
return (
<Suspense fallback={<Text>loading...</Text>}>
<AppInner />
</Suspense>
);
}
3 changes: 2 additions & 1 deletion example/ReactNativeProject/Gemfile
Original file line number Diff line number Diff line change
@@ -3,4 +3,5 @@ source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby ">= 2.6.10"

gem 'cocoapods', '~> 1.12'
gem 'cocoapods', '~> 1.13'
gem 'activesupport', '>= 6.1.7.3', '< 7.1.0'
29 changes: 15 additions & 14 deletions example/ReactNativeProject/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -9,19 +9,19 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
addressable (2.8.5)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
atomos (0.1.3)
claide (1.1.0)
cocoapods (1.12.1)
cocoapods (1.14.3)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
cocoapods-core (= 1.12.1)
cocoapods-core (= 1.14.3)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
cocoapods-downloader (>= 1.6.0, < 2.0)
cocoapods-downloader (>= 2.1, < 3.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-trunk (>= 1.6.0, < 2.0)
@@ -33,8 +33,8 @@ GEM
molinillo (~> 0.8.0)
nap (~> 1.0)
ruby-macho (>= 2.3.0, < 3.0)
xcodeproj (>= 1.21.0, < 2.0)
cocoapods-core (1.12.1)
xcodeproj (>= 1.23.0, < 2.0)
cocoapods-core (1.14.3)
activesupport (>= 5.0, < 8)
addressable (~> 2.8)
algoliasearch (~> 1.0)
@@ -45,7 +45,7 @@ GEM
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
cocoapods-downloader (1.6.3)
cocoapods-downloader (2.1)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
@@ -58,40 +58,41 @@ GEM
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
ffi (1.15.5)
ffi (1.16.3)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
httpclient (2.8.3)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
json (2.6.3)
minitest (5.19.0)
json (2.7.1)
minitest (5.20.0)
molinillo (0.8.0)
nanaimo (0.3.0)
nap (1.1.0)
netrc (0.11.0)
public_suffix (4.0.7)
rexml (3.2.6)
ruby-macho (2.5.1)
typhoeus (1.4.0)
typhoeus (1.4.1)
ethon (>= 0.9.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
xcodeproj (1.22.0)
xcodeproj (1.23.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
colored2 (~> 3.1)
nanaimo (~> 0.3.0)
rexml (~> 3.2.4)
zeitwerk (2.6.11)
zeitwerk (2.6.12)

PLATFORMS
ruby

DEPENDENCIES
cocoapods (~> 1.12)
activesupport (>= 6.1.7.3, < 7.1.0)
cocoapods (~> 1.13)

RUBY VERSION
ruby 2.6.10p210
2 changes: 1 addition & 1 deletion example/ReactNativeProject/__tests__/App.test.tsx
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ import 'react-native';
import React from 'react';
import App from '../App';

// Note: import explicitly to use the types shiped with jest.
// Note: import explicitly to use the types shipped with jest.
import {it} from '@jest/globals';

// Note: test renderer must be required after react-native.
12 changes: 4 additions & 8 deletions example/ReactNativeProject/android/app/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"

/**
@@ -70,8 +71,8 @@ def jscFlavor = 'org.webkit:android-jsc:+'

android {
ndkVersion rootProject.ext.ndkVersion

compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion

namespace "com.reactnativeproject"
defaultConfig {
@@ -106,13 +107,8 @@ android {
dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
implementation("com.facebook.react:flipper-integration")

debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.squareup.okhttp3', module:'okhttp'
}

debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
if (hermesEnabled.toBoolean()) {
implementation("com.facebook.react:hermes-android")
} else {
Original file line number Diff line number Diff line change
@@ -2,12 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<application
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
</application>
tools:ignore="GoogleAppIndexingWarning"/>
</manifest>

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.reactnativeproject

import com.facebook.react.ReactActivity
import com.facebook.react.ReactActivityDelegate
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
import com.facebook.react.defaults.DefaultReactActivityDelegate

class MainActivity : ReactActivity() {

/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
override fun getMainComponentName(): String = "ReactNativeProject"

/**
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
*/
override fun createReactActivityDelegate(): ReactActivityDelegate =
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.reactnativeproject

import android.app.Application
import com.facebook.react.PackageList
import com.facebook.react.ReactApplication
import com.facebook.react.ReactHost
import com.facebook.react.ReactNativeHost
import com.facebook.react.ReactPackage
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.flipper.ReactNativeFlipper
import com.facebook.soloader.SoLoader

class MainApplication : Application(), ReactApplication {

override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> {
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return PackageList(this).packages
}

override fun getJSMainModuleName(): String = "index"

override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG

override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED
}

override val reactHost: ReactHost
get() = getDefaultReactHost(this.applicationContext, reactNativeHost)

override fun onCreate() {
super.onCreate()
SoLoader.init(this, false)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app.
load()
}
ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager)
}
}

This file was deleted.

16 changes: 8 additions & 8 deletions example/ReactNativeProject/android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext {
buildToolsVersion = "33.0.0"
buildToolsVersion = "34.0.0"
minSdkVersion = 21
compileSdkVersion = 33
targetSdkVersion = 33

// We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
ndkVersion = "23.1.7779620"
compileSdkVersion = 34
targetSdkVersion = 34
ndkVersion = "25.1.8937393"
kotlinVersion = "1.8.0"
}
repositories {
google()
@@ -17,5 +14,8 @@ buildscript {
dependencies {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin")
}
}

apply plugin: "com.facebook.react.rootproject"
3 changes: 0 additions & 3 deletions example/ReactNativeProject/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -24,9 +24,6 @@ android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true

# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.182.0

# Use this property to specify which architecture you want to build.
# You can also override it from the CLI using
# ./gradlew <task> -PreactNativeArchitectures=x86_64
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
19 changes: 12 additions & 7 deletions example/ReactNativeProject/android/gradlew
Original file line number Diff line number Diff line change
@@ -83,10 +83,8 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -133,26 +131,29 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi

# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -197,6 +198,10 @@ if "$cygwin" || "$msys" ; then
done
fi


# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'

# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
2 changes: 1 addition & 1 deletion example/ReactNativeProject/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
presets: ['module:@react-native/babel-preset'],
};
24 changes: 24 additions & 0 deletions example/ReactNativeProject/i18n.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'intl-pluralrules';
import i18n from 'i18next';
import {initReactI18next} from 'react-i18next';
import RNLanguageDetector from '@os-team/i18next-react-native-language-detector';

import enTranslation from './locales/en/translation.json';
import deTranslation from './locales/de/translation.json';

i18n
.use(RNLanguageDetector)
.use(initReactI18next)
.init({
debug: true,
fallbackLng: 'en',
supportedLngs: ['en', 'de'],
resources: {
en: {
translation: enTranslation,
},
de: {
translation: deTranslation,
},
},
});
3 changes: 3 additions & 0 deletions example/ReactNativeProject/index.js
Original file line number Diff line number Diff line change
@@ -6,4 +6,7 @@ import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';

// import i18n (needs to be bundled ;))
import './i18n';

AppRegistry.registerComponent(appName, () => App);
7 changes: 0 additions & 7 deletions example/ReactNativeProject/ios/Podfile
Original file line number Diff line number Diff line change
@@ -28,14 +28,8 @@ end
target 'ReactNativeProject' do
config = use_native_modules!

# Flags change depending on the env values.
flags = get_default_flags()

use_react_native!(
:path => config[:reactNativePath],
# Hermes is now enabled by default. Disable by setting this flag to false.
:hermes_enabled => flags[:hermes_enabled],
:fabric_enabled => flags[:fabric_enabled],
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
@@ -57,6 +51,5 @@ target 'ReactNativeProject' do
config[:reactNativePath],
:mac_catalyst_enabled => false
)
__apply_Xcode_12_5_M1_post_install_workaround(installer)
end
end
1,227 changes: 943 additions & 284 deletions example/ReactNativeProject/ios/Podfile.lock

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -177,7 +177,6 @@
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ReactNativeProject" */;
buildPhases = (
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
@@ -378,25 +377,6 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ReactNativeProject-ReactNativeProjectTests/Pods-ReactNativeProject-ReactNativeProjectTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Start Packager";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
@@ -438,7 +418,7 @@
"$(inherited)",
);
INFOPLIST_FILE = ReactNativeProjectTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -462,7 +442,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = ReactNativeProjectTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -536,7 +516,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -580,7 +560,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
@@ -598,9 +578,16 @@
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
};
name = Debug;
};
@@ -609,7 +596,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
@@ -646,7 +633,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
IPHONEOS_DEPLOYMENT_TARGET = 13.4;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
@@ -663,9 +650,16 @@
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
"-DFOLLY_CFG_NO_COROUTINES=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-Wl",
"-ld_classic",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
VALIDATE_PRODUCT = YES;
};
name = Release;
Original file line number Diff line number Diff line change
@@ -15,6 +15,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
return [self getBundleURL];
}

- (NSURL *)getBundleURL
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
12 changes: 4 additions & 8 deletions example/ReactNativeProject/ios/ReactNativeProject/Info.plist
Original file line number Diff line number Diff line change
@@ -26,14 +26,10 @@
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
<key>NSAllowsArbitraryLoads</key>
<false/>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
10 changes: 10 additions & 0 deletions example/ReactNativeProject/locales/de/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"description": {
"part1": "Um loszulegen, ändere <1>src/App(DE).js</1> speichern und neu laden.",
"part2": "Ändere die Sprachen zwischen deutsch und englisch mit Hilfe der beiden Buttons."
},
"new": {
"key": "Dies wird automatisch hinzugefügt"
},
"title": "Willkommen zu React"
}
10 changes: 10 additions & 0 deletions example/ReactNativeProject/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"description": {
"part1": "To get started, edit <1>src/App.js</1> and save to reload.",
"part2": "Switch language between english and german using buttons above."
},
"new": {
"key": "This will be added automatically!!!"
},
"title": "Welcome to React"
}
11,161 changes: 6,129 additions & 5,032 deletions example/ReactNativeProject/package-lock.json

Large diffs are not rendered by default.

27 changes: 14 additions & 13 deletions example/ReactNativeProject/package.json
Original file line number Diff line number Diff line change
@@ -10,30 +10,31 @@
"test": "jest"
},
"dependencies": {
"i18next": "23.4.6",
"@os-team/i18next-react-native-language-detector": "1.0.30",
"i18next": "23.7.15",
"intl-pluralrules": "2.0.1",
"react": "18.2.0",
"react-i18next": "13.2.2",
"react-native": "0.72.4"
"react-i18next": "14.0.0",
"react-native": "0.73.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/preset-env": "^7.20.0",
"@babel/runtime": "^7.20.0",
"@react-native/eslint-config": "^0.72.2",
"@react-native/metro-config": "^0.72.11",
"@tsconfig/react-native": "^3.0.0",
"@types/react": "^18.0.24",
"@react-native/babel-preset": "^0.73.18",
"@react-native/eslint-config": "^0.73.1",
"@react-native/metro-config": "^0.73.2",
"@react-native/typescript-config": "^0.73.1",
"@types/react": "^18.2.6",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.2.1",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"jest": "^29.2.1",
"metro-react-native-babel-preset": "0.76.8",
"prettier": "^2.4.1",
"jest": "^29.6.3",
"prettier": "2.8.8",
"react-test-renderer": "18.2.0",
"typescript": "4.8.4"
"typescript": "5.0.4"
},
"engines": {
"node": ">=16"
"node": ">=18"
}
}
2 changes: 1 addition & 1 deletion example/ReactNativeProject/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "@tsconfig/react-native/tsconfig.json"
"extends": "@react-native/typescript-config/tsconfig.json"
}
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -37,7 +37,7 @@ declare module 'i18next' {
// interface i18n {
// reportNamespaces?: ReportNamespaces;
// }
interface CustomInstanceExtenstions {
interface CustomInstanceExtensions {
reportNamespaces?: ReportNamespaces;
}
}
31,084 changes: 13,231 additions & 17,853 deletions package-lock.json

Large diffs are not rendered by default.

53 changes: 12 additions & 41 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-i18next",
"version": "14.0.0",
"version": "14.0.1",
"description": "Internationalization for react done right. Using the i18next i18n ecosystem.",
"main": "dist/commonjs/index.js",
"types": "./index.d.mts",
@@ -88,15 +88,14 @@
"@testing-library/react": "^11.2.7",
"@testing-library/react-hooks": "^3.4.2",
"@types/react": "^18.2.21",
"@vitest/coverage-v8": "^1.1.1",
"all-contributors-cli": "^6.26.0",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^24.8.0",
"babel-plugin-macros": "^2.5.0",
"babel-plugin-tester": "^6.0.0",
"coveralls": "^3.1.1",
"cp-cli": "^2.0.0",
"cross-env": "^7.0.3",
"dtslint": "^4.2.1",
"eslint": "^8.42.0",
"eslint-config-airbnb": "19.0.4",
"eslint-config-prettier": "^8.8.0",
@@ -105,10 +104,9 @@
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-testing-library": "^5.11.0",
"happy-dom": "^12.10.3",
"husky": "^8.0.3",
"i18next": "^23.7.7",
"jest": "^24.8.0",
"jest-cli": "^24.8.4",
"i18next": "^23.7.17",
"lint-staged": "^8.1.3",
"mkdirp": "^1.0.4",
"prettier": "2.8.8",
@@ -117,9 +115,8 @@
"react-test-renderer": "^16.14.0",
"rimraf": "2.6.3",
"rollup": "3.25.1",
"sinon": "^7.2.3",
"tslint": "^6.1.3",
"typescript": "5.1.3",
"vitest": "1.1.1",
"yargs": "^17.7.2"
},
"peerDependencies": {
@@ -136,6 +133,7 @@
},
"scripts": {
"clean": "rimraf dist && mkdirp dist",
"lint": "eslint ./src ./test",
"copy": "cp-cli ./dist/umd/react-i18next.min.js ./react-i18next.min.js && cp-cli ./dist/umd/react-i18next.js ./react-i18next.js && echo '{\"type\":\"module\"}' > dist/es/package.json",
"build:es": "cross-env BABEL_ENV=jsnext babel src --out-dir dist/es",
"build:cjs": "babel src --out-dir dist/commonjs",
@@ -146,47 +144,20 @@
"fix_dist_package": "node -e 'console.log(`{\"type\":\"module\",\"version\":\"${process.env.npm_package_version}\"}`)' > dist/es/package.json",
"preversion": "npm run build && git push",
"postversion": "npm run fix_dist_package && git push && git push --tags",
"pretest": "npm run test:typescript && npm run test:typescript:noninterop && npm run test:typescript:customtypes",
"test": "cross-env BABEL_ENV=development jest --no-cache",
"test:watch": "cross-env BABEL_ENV=development jest --no-cache --watch",
"test:coverage": "cross-env BABEL_ENV=development jest --no-cache --coverage",
"test:lint": "eslint ./src ./test",
"test:typescript": "tslint --project tsconfig.json '**/*.{ts,tsx}'",
"test:typescript:noninterop": "tslint --project tsconfig.nonEsModuleInterop.json '**/*.{ts,tsx}'",
"test:typescript:customtypes": "tslint --project ./test/typescript/custom-types/tsconfig.json '**/*.{ts,tsx}'",
"pretest": "npm run lint",
"test": "vitest run --typecheck --workspace vitest.workspace.mts",
"test:runtime": "npm run test -- --project runtime",
"test:coverage": "npm run test:runtime -- --coverage --run",
"contributors:add": "all-contributors add",
"contributors:generate": "all-contributors generate",
"prettier": "prettier --write \"{,**/}*.{ts,tsx,js,json,md}\"",
"prettier": "prettier --write \"{,**/}*.{mts,ts,tsx,js,json,md}\"",
"prepare": "husky install"
},
"author": "Jan Mühlemann <jan.muehlemann@gmail.com> (https://github.com/jamuhl)",
"license": "MIT",
"jest": {
"setupFilesAfterEnv": [
"./test/setup.js"
],
"unmockedModulePathPatterns": [
"react"
],
"testMatch": [
"**/test/?(*.)(spec|test).js?(x)"
],
"modulePathIgnorePatterns": [
"<rootDir>/example/"
],
"collectCoverageFrom": [
"**/src/*.{js,jsx}",
"*.macro.js",
"!**/src/index.js",
"!**/src/shallowEqual.js",
"!**/node_modules/**",
"!**/test/**",
"!**/example/**"
]
},
"lint-staged": {
"linters": {
"*.{ts,tsx,js,json,md}": [
"*.{mts,ts,tsx,js,json,md}": [
"prettier --write",
"git add"
]
1,676 changes: 830 additions & 846 deletions react-i18next.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion react-i18next.min.js

Large diffs are not rendered by default.

20 changes: 16 additions & 4 deletions src/TransWithoutContext.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { isValidElement, cloneElement, createElement, Children } from 'react';
import { Fragment, isValidElement, cloneElement, createElement, Children } from 'react';
import HTML from 'html-parse-stringify';
import { warn, warnOnce } from './utils.js';
import { getDefaults } from './defaults.js';
@@ -156,7 +156,16 @@ function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts, s
...Children.map([child], (c) => {
const props = { ...c.props };
delete props.i18nIsDynamicList;
return <c.type {...props} key={i} ref={c.ref} {...(isVoid ? {} : { children: inner })} />;
// <c.type {...props} key={i} ref={c.ref} {...(isVoid ? {} : { children: inner })} />;
return createElement(
c.type,
{
...props,
key: i,
ref: c.ref,
},
isVoid ? null : inner,
);
}),
);
}
@@ -365,11 +374,14 @@ export function Trans({
(translation.indexOf(`${c}/>`) < 0 && translation.indexOf(`${c} />`) < 0)
)
return;

// eslint-disable-next-line react/no-unstable-nested-components, no-inner-declarations
function Componentized() {
return <>{comp}</>;
// <>{comp}</>
return createElement(Fragment, null, comp);
}
components[c] = <Componentized />;
// <Componentized />
components[c] = createElement(Componentized);
});
}

12 changes: 0 additions & 12 deletions test/.eslintrc

This file was deleted.

9 changes: 9 additions & 0 deletions test/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": ["plugin:testing-library/react", "plugin:jest-dom/recommended"],
"globals": {
"globalThis": false
},
"rules": {
"testing-library/no-node-access": ["error", { "allowContainerFirstChild": true }]
}
}
11 changes: 8 additions & 3 deletions test/I18nextProvider.spec.js → test/I18nextProvider.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { describe, it, expect, vitest, afterEach } from 'vitest';
import React from 'react';
import { render, screen } from '@testing-library/react';
import { render, screen, cleanup } from '@testing-library/react';
import { I18nextProvider } from '../src/I18nextProvider';
import { useTranslation } from '../src/useTranslation';

jest.unmock('../src/useTranslation');
jest.unmock('../src/I18nextProvider');
vitest.unmock('../src/useTranslation');
vitest.unmock('../src/I18nextProvider');

const instance = {
language: 'en',
@@ -26,6 +27,10 @@ const instance = {
};

describe('I18nextProvider', () => {
afterEach(() => {
cleanup();
});

it('should render correct content', () => {
function TestComponent() {
const { t, i18n } = useTranslation('translation');
9 changes: 7 additions & 2 deletions test/Translation.spec.js → test/Translation.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { describe, it, vitest, expect, afterEach } from 'vitest';
import React from 'react';
import { render } from '@testing-library/react';
import { render, cleanup } from '@testing-library/react';
import './i18n';
import { Translation } from '../src/Translation';

jest.unmock('../src/Translation');
vitest.unmock('../src/Translation');

describe('Translation', () => {
afterEach(() => {
cleanup();
});

function TestComponent() {
return <Translation>{(t) => <div>{t('key1')}</div>}</Translation>;
}
230 changes: 115 additions & 115 deletions test/__snapshots__/icu.macro.spec.js.snap

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions test/lngAwareBackendMock.js → test/backendLngAwareMock.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Backend {
export class BackendLngAwareMock {
constructor(services, options = {}) {
this.init(services, options);
this.type = 'backend';
@@ -28,13 +28,13 @@ class Backend {
});
}
}

q.forEach((item) => {
this.queue.splice(this.queue.indexOf(item), 1);

item.callback(null, {
key1: `${item.language}/${item.namespace} for key1`,
});
});
}
}

export default Backend;
4 changes: 1 addition & 3 deletions test/backendMock.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class Backend {
export class BackendMock {
constructor(services, options = {}) {
this.init(services, options);
this.type = 'backend';
@@ -23,5 +23,3 @@ class Backend {
});
}
}

export default Backend;
12 changes: 12 additions & 0 deletions test/icu.macro.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import { describe, it, expect } from 'vitest';
import pluginTester from 'babel-plugin-tester';
import plugin from 'babel-plugin-macros';

/**
* babel-plugin-tester in icu.macro.spec.js need test function exposed in globals scope.
*
* Instead of exposing globals using relative --globals flag I exposed utilities only for this file
* @see https://github.com/babel-utils/babel-plugin-tester#vitest
*/

globalThis.describe = describe;
globalThis.it = it;
globalThis.expect = expect;

pluginTester({
plugin,
snapshot: true,
5 changes: 4 additions & 1 deletion test/setup.js
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
import '@testing-library/jest-dom';
import matchers from '@testing-library/jest-dom/matchers';
import { expect } from 'vitest';

expect.extend(matchers);
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { describe, it, expect } from 'vitest';
import React from 'react';
import { nodesToString } from '../src/Trans';

describe('trans nodeToString', () => {
describe('trans nodeToString', () => {
describe('treat like other components (legacy)', () => {
it('should handle voidElements eg. br', () => {
const fragment = (
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { describe, it, expect, afterEach } from 'vitest';
import React from 'react';
import { render } from '@testing-library/react';
import { render, cleanup } from '@testing-library/react';
import './i18n';
import { Trans } from '../src';

describe('Trans should render nested components', () => {
// beforeAll(() => {
// vitest.spyOn(console, 'error').mockImplementation(() => { });
// })

afterEach(() => {
cleanup();
// vitest.clearAllMocks();
});

it('should render dynamic ul as components property', () => {
const list = ['li1', 'li2'];

Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { describe, it, expect, afterEach } from 'vitest';
import React from 'react';
import { render } from '@testing-library/react';
import { render, cleanup } from '@testing-library/react';
import './i18n';
import { Trans } from '../src/Trans';

describe('trans using no children but props - icu case', () => {
afterEach(() => {
cleanup();
});

function TestComponent() {
return (
<Trans
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { describe, it, expect, afterEach } from 'vitest';
import React from 'react';
import { render } from '@testing-library/react';
import { render, cleanup } from '@testing-library/react';
import './i18n';
import { Trans } from '../src/Trans';

describe('trans using no children but components (object) - base case using array not object', () => {
afterEach(() => {
cleanup();
});

function TestComponent() {
return (
<Trans
7 changes: 6 additions & 1 deletion test/trans.render.spec.js → test/trans.render.spec.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, it, expect, beforeAll, afterAll, afterEach } from 'vitest';
import React from 'react';
import { render } from '@testing-library/react';
import { render, cleanup } from '@testing-library/react';
import i18n from './i18n';
import { withTranslation } from '../src/withTranslation';
import { Trans } from '../src/Trans';
@@ -9,6 +10,10 @@ function Link({ to, children }) {
}

describe('trans simple', () => {
afterEach(() => {
cleanup();
});

function TestComponent({ parent }) {
return (
<Trans i18nKey="transTest1" parent={parent}>
41 changes: 0 additions & 41 deletions test/typescript/I18nextProvider.test.tsx

This file was deleted.

107 changes: 0 additions & 107 deletions test/typescript/Trans.test.tsx

This file was deleted.

99 changes: 0 additions & 99 deletions test/typescript/TransWithoutContext.test.tsx

This file was deleted.

24 changes: 0 additions & 24 deletions test/typescript/Translation.test.tsx

This file was deleted.

10 changes: 0 additions & 10 deletions test/typescript/context.test.tsx

This file was deleted.

231 changes: 117 additions & 114 deletions test/typescript/custom-types/Trans.test.tsx
Original file line number Diff line number Diff line change
@@ -1,117 +1,120 @@
import { describe, it, expectTypeOf } from 'vitest';
import * as React from 'react';
import { Trans, useTranslation } from 'react-i18next';

function defaultNamespaceUsage() {
return <Trans i18nKey="foo">foo</Trans>;
}

function namedDefaultNamespaceUsage() {
return (
<Trans ns="custom" i18nKey="foo">
foo
</Trans>
);
}

function alternateNamespaceUsage() {
return (
<Trans ns="alternate" i18nKey="baz">
foo
</Trans>
);
}

function arrayNamespace() {
return (
<Trans ns={['alternate', 'custom']} i18nKey={['alternate:baz', 'custom:bar']}>
foo
</Trans>
);
}

function withTfunction() {
const { t } = useTranslation('alternate');

return (
<Trans t={t} i18nKey="foobar.barfoo">
foo
</Trans>
);
}

function withTfunctionAndKeyPrefix() {
const { t } = useTranslation('alternate', { keyPrefix: 'foobar.deep' });

return (
<Trans t={t} i18nKey="deeper.deeeeeper">
foo
</Trans>
);
}

function expectErrorWhenNamespaceDoesNotExist() {
return (
// @ts-expect-error
<Trans ns="fake" i18nKey="foo">
foo
</Trans>
);
}

function expectErrorWhenKeyNotInNamespace() {
return (
// @ts-expect-error
<Trans ns="custom" i18nKey="fake">
foo
</Trans>
);
}

// function expectErrorWhenUsingArrayNamespaceAndUnscopedKey() {
// return (
// // @ts-expect-error
// <Trans ns={['custom']} i18nKey={['foo']}>
// foo
// </Trans>
// );
// }

function expectErrorWhenUsingArrayNamespaceAndWrongKey() {
return (
// @ts-expect-error
<Trans ns={['custom']} i18nKey={['custom:fake']}>
foo
</Trans>
);
}

function withTfunctionAndKeyPrefixAndWrongKey() {
const { t } = useTranslation('alternate', { keyPrefix: 'foobar.deep' });

return (
// @ts-expect-error
<Trans t={t} i18nKey="xxx">
foo
</Trans>
);
}

function withTextAndInterpolation() {
return <Trans>foo {{ var: '' }}</Trans>;
}

function withInterpolationInHTMLElement() {
return (
<Trans>
foo <strong>{{ var: '' }}</strong>
</Trans>
);
}

function withTextAndInterpolationChildrenInHTMLElement() {
return (
<Trans>
<span>foo {{ var: '' }}</span>
</Trans>
);
}
describe('<Trans />', () => {
describe('default namespace', () => {
it('standard usage', () => {
// <Trans i18nKey="foo">foo</Trans>
expectTypeOf(Trans).toBeCallableWith({
i18nKey: 'foo',
});
});

it('should trow if key do not exist', () => {
expectTypeOf<React.ComponentProps<typeof Trans>>()
.toHaveProperty('i18nKey')
.extract<'Nope'>()
// @ts-expect-error
.toMatchTypeOf<'Nope'>();
});
});

describe('named namespace', () => {
it('standard usage', () => {
// <Trans ns="custom" i18nKey="foo">foo</Trans>
expectTypeOf(Trans).toBeCallableWith({
ns: 'custom',
i18nKey: 'foo',
});
});

it('should trow if namespace do not exist', () => {
expectTypeOf<React.ComponentProps<typeof Trans>>()
.toHaveProperty('ns')
.extract<'Nope'>()
// @ts-expect-error
.toMatchTypeOf<'Nope'>();
});
});

describe('array namespace', () => {
it('should work with array namespace', () => {
// <Trans ns={['alternate', 'custom']} i18nKey={['alternate:baz', 'custom:bar']} />
expectTypeOf(Trans).toBeCallableWith({
ns: ['alternate', 'custom'],
i18nKey: ['alternate:baz', 'custom:bar'],
});
});

it('should throw error if key is not present inside namespaces', () => {
// <Trans ns={['alternate', 'custom']} i18nKey={['alternate:baz', 'custom:bar']} />
expectTypeOf(Trans).toBeCallableWith({
ns: ['alternate', 'custom'],
// @ts-expect-error
i18nKey: ['alternate:baz', 'custom:bar2'],
});
});
});

describe('usage with `t` function', () => {
it('should work when providing `t` function', () => {
const { t } = useTranslation('alternate');

// <Trans t={t} i18nKey="foobar.barfoo">foo</Trans>
expectTypeOf(Trans).toBeCallableWith({
t,
i18nKey: 'foobar.barfoo',
});
});

it('should work when providing `t` function with a prefix', () => {
const { t } = useTranslation('alternate', { keyPrefix: 'foobar.deep' });

// <Trans t={t} i18nKey="deeper.deeeeeper">foo</Trans>
expectTypeOf<
typeof Trans<'deeper.deeeeeper', 'alternate', {}, 'foobar.deep'>
>().toBeCallableWith({
t,
i18nKey: 'deeper.deeeeeper',
});
});

it('should throw error with `t` function with key prefix and wrong `i18nKey`', () => {
const { t } = useTranslation('alternate', { keyPrefix: 'foobar.deep' });

// <Trans t={t} i18nKey="xxx">foo</Trans>
expectTypeOf<
typeof Trans<'deeper.deeeeeper', 'alternate', {}, 'foobar.deep'>
>().toBeCallableWith({
t,
// @ts-expect-error
i18nKey: 'xxx',
});
});
});

describe('interpolation', () => {
it('should work with text and interpolation', () => {
expectTypeOf(Trans).toBeCallableWith({
children: <>foo {{ var: '' }}</>,
});
});

it('should work with Interpolation in HTMLElement', () => {
expectTypeOf(Trans).toBeCallableWith({
children: (
<>
foo <strong>{{ var: '' }}</strong>
</>
),
});
});

it('should work with text and interpolation as children of an HTMLElement', () => {
expectTypeOf(Trans).toBeCallableWith({
children: <span>foo {{ var: '' }}</span>,
});
});
});
});
185 changes: 104 additions & 81 deletions test/typescript/custom-types/TransWithoutContext.test.tsx
Original file line number Diff line number Diff line change
@@ -1,98 +1,121 @@
import { describe, it, expectTypeOf } from 'vitest';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { Trans } from '../../../TransWithoutContext';

function defaultNamespaceUsage() {
return <Trans i18nKey="foo">foo</Trans>;
}
describe('<Trans />', () => {
describe('default namespace', () => {
it('standard usage', () => {
// <Trans i18nKey="foo">foo</Trans>
expectTypeOf(Trans).toBeCallableWith({
i18nKey: 'foo',
});
});

function namedDefaultNamespaceUsage() {
return (
<Trans ns="custom" i18nKey="foo">
foo
</Trans>
);
}
it('should trow if key do not exist', () => {
expectTypeOf<React.ComponentProps<typeof Trans>>()
.toHaveProperty('i18nKey')
.extract<'Nope'>()
// @ts-expect-error
.toMatchTypeOf<'Nope'>();
});
});

function alternateNamespaceUsage() {
return (
<Trans ns="alternate" i18nKey="baz">
foo
</Trans>
);
}
describe('named namespace', () => {
it('standard usage', () => {
// <Trans ns="custom" i18nKey="foo">foo</Trans>
expectTypeOf(Trans).toBeCallableWith({
ns: 'custom',
i18nKey: 'foo',
});
});

function arrayNamespace() {
return (
<Trans ns={['alternate', 'custom']} i18nKey={['alternate:baz', 'custom:bar']}>
foo
</Trans>
);
}
it('should trow if namespace do not exist', () => {
expectTypeOf<React.ComponentProps<typeof Trans>>()
.toHaveProperty('ns')
.extract<'Nope'>()
// @ts-expect-error
.toMatchTypeOf<'Nope'>();
});
});

function withTfunction() {
const { t } = useTranslation('alternate');
describe('array namespace', () => {
it('should work with array namespace', () => {
// <Trans ns={['alternate', 'custom']} i18nKey={['alternate:baz', 'custom:bar']} />
expectTypeOf(Trans).toBeCallableWith({
ns: ['alternate', 'custom'],
i18nKey: ['alternate:baz', 'custom:bar'],
});
});

return (
<Trans t={t} i18nKey="foobar.barfoo">
foo
</Trans>
);
}
it('should throw error if key is not present inside namespaces', () => {
// <Trans ns={['alternate', 'custom']} i18nKey={['alternate:baz', 'custom:bar']} />
expectTypeOf(Trans).toBeCallableWith({
ns: ['alternate', 'custom'],
// @ts-expect-error
i18nKey: ['alternate:baz', 'custom:bar2'],
});
});
});

function withTfunctionAndKeyPrefix() {
const { t } = useTranslation('alternate', { keyPrefix: 'foobar.deep' });
describe('usage with `t` function', () => {
it('should work when providing `t` function', () => {
const { t } = useTranslation('alternate');

return (
<Trans t={t} i18nKey="deeper.deeeeeper">
foo
</Trans>
);
}
// <Trans t={t} i18nKey="foobar.barfoo">foo</Trans>
expectTypeOf(Trans).toBeCallableWith({
t,
i18nKey: 'foobar.barfoo',
});
});

function expectErrorWhenNamespaceDoesNotExist() {
return (
// @ts-expect-error
<Trans ns="fake" i18nKey="foo">
foo
</Trans>
);
}
it('should work when providing `t` function with a prefix', () => {
const { t } = useTranslation('alternate', { keyPrefix: 'foobar.deep' });

function expectErrorWhenKeyNotInNamespace() {
return (
// @ts-expect-error
<Trans ns="custom" i18nKey="fake">
foo
</Trans>
);
}
// <Trans t={t} i18nKey="deeper.deeeeeper">foo</Trans>
expectTypeOf<
typeof Trans<'deeper.deeeeeper', 'alternate', {}, 'foobar.deep'>
>().toBeCallableWith({
t,
i18nKey: 'deeper.deeeeeper',
});
});

// function expectErrorWhenUsingArrayNamespaceAndUnscopedKey() {
// return (
// // @ts-expect-error
// <Trans ns={['custom']} i18nKey={['foo']}>
// foo
// </Trans>
// );
// }
it('should throw error with `t` function with key prefix and wrong `i18nKey`', () => {
const { t } = useTranslation('alternate', { keyPrefix: 'foobar.deep' });

function expectErrorWhenUsingArrayNamespaceAndWrongKey() {
return (
// @ts-expect-error
<Trans ns={['custom']} i18nKey={['custom:fake']}>
foo
</Trans>
);
}
// <Trans t={t} i18nKey="xxx">foo</Trans>
expectTypeOf<
typeof Trans<'deeper.deeeeeper', 'alternate', {}, 'foobar.deep'>
>().toBeCallableWith({
t,
// @ts-expect-error
i18nKey: 'xxx',
});
});
});

function withTfunctionAndKeyPrefixAndWrongKey() {
const { t } = useTranslation('alternate', { keyPrefix: 'foobar.deep' });
describe('interpolation', () => {
it('should work with text and interpolation', () => {
expectTypeOf(Trans).toBeCallableWith({
children: <>foo {{ var: '' }}</>,
});
});

return (
// @ts-expect-error
<Trans t={t} i18nKey="xxx">
foo
</Trans>
);
}
it('should work with Interpolation in HTMLElement', () => {
expectTypeOf(Trans).toBeCallableWith({
children: (
<>
foo <strong>{{ var: '' }}</strong>
</>
),
});
});

it('should work with text and interpolation as children of an HTMLElement', () => {
expectTypeOf(Trans).toBeCallableWith({
children: <span>foo {{ var: '' }}</span>,
});
});
});
});
41 changes: 41 additions & 0 deletions test/typescript/custom-types/Translation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { describe, it, expectTypeOf } from 'vitest';
import { Translation } from 'react-i18next';

describe('<Translation />', () => {
it('should work with default namespace', () => {
expectTypeOf(Translation).toBeCallableWith({ children: (t) => t('foo') });
});

it('should work with named default namespace', () => {
expectTypeOf(Translation<'custom'>).toBeCallableWith({ children: (t) => t('foo') });
});

it('should work with named namespace', () => {
expectTypeOf(Translation<'alternate'>).toBeCallableWith({ children: (t) => t('baz') });
});

it('should work with namespace array', () => {
expectTypeOf(Translation<['alternate', 'custom']>).toBeCallableWith({
children: (t) => `${t('alternate:baz')} ${t('custom:foo')}`,
});
});

it('should throw error when namespace does not exist', () => {
// @ts-expect-error
expectTypeOf(Translation<'fake'>).toBeFunction();
});

it('should throw error when namespace does not contain given `t` key', () => {
expectTypeOf(Translation<'custom'>).toBeCallableWith({
// @ts-expect-error
children: (t) => t('fake'),
});
});

it('should throw error when namespace does not contain given `t` key (with namespace as prefix)', () => {
expectTypeOf(Translation<'custom'>).toBeCallableWith({
// @ts-expect-error
children: (t) => t('custom:fake'),
});
});
});
42 changes: 0 additions & 42 deletions test/typescript/custom-types/Translation.test.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -8,6 +8,8 @@ declare module 'i18next' {
custom: {
foo: 'foo';
bar: 'bar';
some: 'some';
some_me: 'some context';
};
alternate: {
baz: 'baz';
111 changes: 111 additions & 0 deletions test/typescript/custom-types/useTranslation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { describe, it, expectTypeOf, assertType } from 'vitest';
import { useTranslation } from 'react-i18next';
import { TFunction, i18n } from 'i18next';

describe('useTranslation', () => {
it('should provide result with both object and array', () => {
const result = useTranslation();

expectTypeOf(result).toMatchTypeOf<[TFunction, i18n, boolean]>();
expectTypeOf(result).toHaveProperty('ready').toBeBoolean();
expectTypeOf(result).toHaveProperty('t').toBeFunction();
expectTypeOf(result).toHaveProperty('i18n').toBeObject();
});

describe('default namespace', () => {
it('should work with default namespace', () => {
const [t] = useTranslation();

expectTypeOf(t).toBeCallableWith('foo');
});

it('should work with default named namespace', () => {
const [t] = useTranslation('custom');

expectTypeOf(t).toBeCallableWith('bar');
});
});

describe('named namespace', () => {
it('should work with named namespace', () => {
const [t] = useTranslation('alternate');

expectTypeOf(t).toBeCallableWith('baz');
});

it('should throw error when namespace does not exist', () => {
// @ts-expect-error
const [t] = useTranslation('fake');
});

it('should throw error when key does not exist inside namespace', () => {
const [t] = useTranslation('custom');
// @ts-expect-error
assertType<string>(t('fake'));
});
});

describe('namespace as array', () => {
it('should work with const namespaces', () => {
const [t] = useTranslation(['alternate', 'custom']);

expectTypeOf(t('alternate:baz')).toEqualTypeOf<'baz'>();
expectTypeOf(t('baz', { ns: 'alternate' })).toEqualTypeOf<'baz'>();
expectTypeOf(t('custom:foo')).toEqualTypeOf<'foo'>();
expectTypeOf(t('foo', { ns: 'custom' })).toEqualTypeOf<'foo'>();
});

it('should work with const namespaces', () => {
const namespaces = ['alternate', 'custom'] as const;
const [t] = useTranslation(namespaces);

expectTypeOf(t('alternate:baz')).toEqualTypeOf<'baz'>();
expectTypeOf(t('baz', { ns: 'alternate' })).toEqualTypeOf<'baz'>();
expectTypeOf(t('custom:foo')).toEqualTypeOf<'foo'>();
expectTypeOf(t('foo', { ns: 'custom' })).toEqualTypeOf<'foo'>();
});

it('should throw error when using wrong key', () => {
const [t] = useTranslation(['custom']);
// @ts-expect-error
assertType<string>(t('custom:fake'));
// @ts-expect-error
assertType<string>(t('fake', { ns: 'custom' }));
});
});

describe('with `keyPrefix`', () => {
it('should provide string keys', () => {
const [t] = useTranslation('alternate', { keyPrefix: 'foobar' });

expectTypeOf(t('barfoo')).toEqualTypeOf<'barfoo'>();
});

it('should work with deeper objects', () => {
const [t] = useTranslation('alternate', { keyPrefix: 'foobar.deep' });

expectTypeOf(t('deeper', { returnObjects: true })).toEqualTypeOf<{
deeeeeper: 'foobar';
}>();
expectTypeOf(t('deeper.deeeeeper')).toEqualTypeOf<'foobar'>();
});

it('should throw error with an invalid keyPrefix', () => {
// @ts-expect-error
useTranslation('alternate', { keyPrefix: 'abc' });
});

it('should throw error with an invalid key', () => {
const [t] = useTranslation('alternate', { keyPrefix: 'foobar' });
// @ts-expect-error
assertType<string>(t('abc'));
});
});

it('should work with json format v4 plurals', () => {
const [t] = useTranslation('plurals');

expectTypeOf(t('foo')).toEqualTypeOf<'foo'>();
expectTypeOf(t('foo_one')).toEqualTypeOf<'foo'>();
});
});
100 changes: 0 additions & 100 deletions test/typescript/custom-types/useTranslation.test.tsx

This file was deleted.

Loading