Skip to content

Commit

Permalink
create a isString helper to avoid code duplication (#1763)
Browse files Browse the repository at this point in the history
* create a isString helper to avoid code duplication

* add test
  • Loading branch information
VIKTORVAV99 authored Jul 15, 2024
1 parent 46e8ea5 commit a904e07
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 16 deletions.
12 changes: 6 additions & 6 deletions src/TransWithoutContext.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Fragment, isValidElement, cloneElement, createElement, Children } from 'react';
import HTML from 'html-parse-stringify';
import { warn, warnOnce } from './utils.js';
import { isString, warn, warnOnce } from './utils.js';
import { getDefaults } from './defaults.js';
import { getI18n } from './i18nInstance.js';

Expand Down Expand Up @@ -44,7 +44,7 @@ export const nodesToString = (children, i18nOptions) => {

// e.g. lorem <br/> ipsum {{ messageCount, format }} dolor <strong>bold</strong> amet
childrenArray.forEach((child, childIndex) => {
if (typeof child === 'string') {
if (isString(child)) {
// actual e.g. lorem
// expected e.g. lorem
stringNode += `${child}`;
Expand All @@ -66,7 +66,7 @@ export const nodesToString = (children, i18nOptions) => {
// e.g. <ul i18nIsDynamicList>{['a', 'b'].map(item => ( <li key={item}>{item}</li> ))}</ul>
// expected e.g. "<0></0>", not e.g. "<0><0>a</0><1>b</1></0>"
stringNode += `<${childIndex}></${childIndex}>`;
} else if (shouldKeepChild && childPropsCount === 1 && typeof childChildren === 'string') {
} else if (shouldKeepChild && childPropsCount === 1 && isString(childChildren)) {
// actual e.g. dolor <strong>bold</strong> amet
// expected e.g. dolor <strong>bold</strong> amet
stringNode += `<${child.type}>${childChildren}</${child.type}>`;
Expand Down Expand Up @@ -121,7 +121,7 @@ const renderNodes = (children, targetString, i18n, i18nOptions, combinedTOpts, s
const childrenArray = getAsArray(childs);

childrenArray.forEach((child) => {
if (typeof child === 'string') return;
if (isString(child)) return;
if (hasChildren(child)) getData(getChildren(child));
else if (typeof child === 'object' && !isValidElement(child)) Object.assign(data, child);
});
Expand Down Expand Up @@ -209,7 +209,7 @@ const renderNodes = (children, targetString, i18n, i18nOptions, combinedTOpts, s
children !== null &&
Object.hasOwnProperty.call(children, node.name);

if (typeof child === 'string') {
if (isString(child)) {
const value = i18n.services.interpolator.interpolate(child, opts, i18n.language);
mem.push(value);
} else if (
Expand Down Expand Up @@ -331,7 +331,7 @@ export function Trans({

// prepare having a namespace
let namespaces = ns || t.ns || (i18n.options && i18n.options.defaultNS);
namespaces = typeof namespaces === 'string' ? [namespaces] : namespaces || ['translation'];
namespaces = isString(namespaces) ? [namespaces] : namespaces || ['translation'];

const nodeAsString = nodesToString(children, reactI18nextOptions);
const defaultValue =
Expand Down
8 changes: 4 additions & 4 deletions src/useTranslation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useEffect, useContext, useRef, useCallback } from 'react';
import { getI18n, getDefaults, ReportNamespaces, I18nContext } from './context.js';
import { warnOnce, loadNamespaces, loadLanguages, hasLoadedNamespace } from './utils.js';
import { warnOnce, loadNamespaces, loadLanguages, hasLoadedNamespace, isString } from './utils.js';

const usePrevious = (value, ignore) => {
const ref = useRef();
Expand Down Expand Up @@ -30,11 +30,11 @@ export const useTranslation = (ns, props = {}) => {
if (!i18n) {
warnOnce('You will need to pass in an i18next instance by using initReactI18next');
const notReadyT = (k, optsOrDefaultValue) => {
if (typeof optsOrDefaultValue === 'string') return optsOrDefaultValue;
if (isString(optsOrDefaultValue)) return optsOrDefaultValue;
if (
optsOrDefaultValue &&
typeof optsOrDefaultValue === 'object' &&
typeof optsOrDefaultValue.defaultValue === 'string'
isString(optsOrDefaultValue.defaultValue)
)
return optsOrDefaultValue.defaultValue;
return Array.isArray(k) ? k[k.length - 1] : k;
Expand All @@ -56,7 +56,7 @@ export const useTranslation = (ns, props = {}) => {

// prepare having a namespace
let namespaces = ns || defaultNSFromContext || (i18n.options && i18n.options.defaultNS);
namespaces = typeof namespaces === 'string' ? [namespaces] : namespaces || ['translation'];
namespaces = isString(namespaces) ? [namespaces] : namespaces || ['translation'];

// report namespaces as used
if (i18n.reportNamespaces.addUsedNamespaces) i18n.reportNamespaces.addUsedNamespaces(namespaces);
Expand Down
14 changes: 8 additions & 6 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
// Do not use arrow function here as it will break optimizations of arguments
export function warn(...args) {
if (console && console.warn) {
if (typeof args[0] === 'string') args[0] = `react-i18next:: ${args[0]}`;
if (isString(args[0])) args[0] = `react-i18next:: ${args[0]}`;
console.warn(...args);
}
}

const alreadyWarned = {};
// Do not use arrow function here as it will break optimizations of arguments
export function warnOnce(...args) {
if (typeof args[0] === 'string' && alreadyWarned[args[0]]) return;
if (typeof args[0] === 'string') alreadyWarned[args[0]] = new Date();
if (isString(args[0]) && alreadyWarned[args[0]]) return;
if (isString(args[0])) alreadyWarned[args[0]] = new Date();
warn(...args);
}

// not needed right now
//
// export function deprecated(...args) {
// if (process && process.env && (!process.env.NODE_ENV || process.env.NODE_ENV === 'development')) {
// if (typeof args[0] === 'string') args[0] = `deprecation warning -> ${args[0]}`;
// if (isString(args[0])) args[0] = `deprecation warning -> ${args[0]}`;
// warnOnce(...args);
// }
// }
Expand Down Expand Up @@ -46,7 +46,7 @@ export const loadNamespaces = (i18n, ns, cb) => {
// should work with I18NEXT >= v22.5.0
export const loadLanguages = (i18n, lng, ns, cb) => {
// eslint-disable-next-line no-param-reassign
if (typeof ns === 'string') ns = [ns];
if (isString(ns)) ns = [ns];
ns.forEach((n) => {
if (i18n.options.ns.indexOf(n) < 0) i18n.options.ns.push(n);
});
Expand Down Expand Up @@ -127,4 +127,6 @@ export const hasLoadedNamespace = (ns, i18n, options = {}) => {
export const getDisplayName = (Component) =>
Component.displayName ||
Component.name ||
(typeof Component === 'string' && Component.length > 0 ? Component : 'Unknown');
(isString(Component) && Component.length > 0 ? Component : 'Unknown');

export const isString = (obj) => typeof obj === 'string';
15 changes: 15 additions & 0 deletions test/utils.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { describe, it, expect } from 'vitest';
import { isString } from '../src/utils.js';

describe('isString', () => {
it('should return true for strings', () => {
expect(isString('string')).toBe(true);
});

it.each([[undefined], [null], [1], [{}], [[]], [() => {}]])(
'should return false for non-strings, testing %o',
(value) => {
expect(isString(value)).toBe(false);
},
);
});

0 comments on commit a904e07

Please sign in to comment.