react-native-i18n-auto
Version:
Auto i18n tool for React Native with full TypeScript support
113 lines (96 loc) • 4.52 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = _default;
function _default(_ref) {
var babelTypes = _ref.types;
// Function to convert text to key
function parseToKey(text) {
return text.trim()
// Convert camelCase to underscore (e.g., userName -> user_name)
.replace(/([a-z])([A-Z])/g, '$1_$2')
// Convert spaces to underscores
.replace(/\s+/g, '_')
// Remove special characters (keep only alphanumeric and underscore)
.replace(/[^A-Za-z0-9_]/g, '')
// Convert to uppercase
.toUpperCase();
}
return {
visitor: {
Program: {
exit: function exit(path, state) {
// Check if i18n is actually used
if (!state.i18nUsed) return;
// Check if there is an i18n import statement
var hasI18nImport = path.node.body.some(function (node) {
var _node$source, _node$specifiers;
return babelTypes.isImportDeclaration(node) && ((_node$source = node.source) === null || _node$source === void 0 ? void 0 : _node$source.value) === 'react-native-i18n-auto' && ((_node$specifiers = node.specifiers) === null || _node$specifiers === void 0 ? void 0 : _node$specifiers.some(function (specifier) {
return babelTypes.isImportSpecifier(specifier) && 'name' in specifier.imported && specifier.imported.name === 'i18n';
}));
});
// Add import statement if it doesn't exist
if (!hasI18nImport) {
var importDeclaration = babelTypes.importDeclaration([babelTypes.importSpecifier(babelTypes.identifier('i18n'), babelTypes.identifier('i18n'))], babelTypes.stringLiteral('react-native-i18n-auto'));
// Add an empty line for line breaks
var emptyStatement = babelTypes.emptyStatement();
path.node.body.unshift(emptyStatement);
path.node.body.unshift(importDeclaration);
}
}
},
JSXText: function JSXText(path, state) {
var text = path.node.value.trim();
if (!text) return;
// Ignore if it contains JSX expressions or dynamic values
if (text.includes('{') || text.includes('}')) return;
// Check if it's a prop value like title, placeholder, etc.
var parent = path.parentPath;
if (parent && babelTypes.isJSXAttribute(parent.node)) return;
// Ignore if the text is just whitespace or line breaks
if (/^[\s\n]*$/.test(text)) return;
// Indicate that i18n is used
state.i18nUsed = true;
// Save extracted text
if (state.opts.extractedTexts) {
state.opts.extractedTexts.add(text);
if (!state.file.metadata.extractedCount) {
state.file.metadata.extractedCount = 0;
}
state.file.metadata.extractedCount++;
}
// Generate key
var key = parseToKey(text);
// Convert to i18n.t() call
var i18nExpression = babelTypes.jsxExpressionContainer(babelTypes.callExpression(babelTypes.memberExpression(babelTypes.identifier('i18n'), babelTypes.identifier('t')), [babelTypes.stringLiteral(key)]));
// Replace original text with the converted expression
path.replaceWith(i18nExpression);
},
JSXAttribute: function JSXAttribute(path, state) {
var node = path.node;
// Only process string props like title, placeholder, etc.
if (babelTypes.isStringLiteral(node.value) && babelTypes.isJSXIdentifier(node.name) && ['title', 'placeholder', 'label', 'text'].includes(node.name.name)) {
var value = node.value.value.trim();
if (!value) return;
// Indicate that i18n is used
state.i18nUsed = true;
// Save extracted text
if (state.opts.extractedTexts) {
state.opts.extractedTexts.add(value);
if (!state.file.metadata.extractedCount) {
state.file.metadata.extractedCount = 0;
}
state.file.metadata.extractedCount++;
}
// Generate key
var key = parseToKey(value);
// Convert to i18n.t() call
var i18nExpression = babelTypes.jsxExpressionContainer(babelTypes.callExpression(babelTypes.memberExpression(babelTypes.identifier('i18n'), babelTypes.identifier('t')), [babelTypes.stringLiteral(key)]));
// Replace prop value with the converted expression
node.value = i18nExpression;
}
}
}
};
}