Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 46 additions & 1 deletion scripts/check-i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ const I18N_PROPS = [
'alt',
];

const I18N_OBJECT_KEYS = [
'label',
'description',
'placeholder',
'subtitle',
'heading',
'tooltip',
];

const CLASS_LIKE = /[-/:[\]]/;

const SKIP_LINE_PATTERNS = [
/^\s*\/\//,
/^\s*\*/,
Expand Down Expand Up @@ -90,9 +101,43 @@ function checkFile(filePath: string): Violation[] {
});
}
}

for (const key of I18N_OBJECT_KEYS) {
const keyRegex = new RegExp(
`(?:^|[\\s,{(])${key}\\s*:\\s*(['"])([^'"]*[a-zA-Z]{2,}[^'"]*)\\1`,
'g',
);
for (const m of line.matchAll(keyRegex)) {
if (CLASS_LIKE.test(m[2])) continue;
violations.push({
file: rel,
line: i + 1,
text: trimmed,
reason: `hardcoded ${key}: "${m[2]}"`,
});
}
}

const exprRegex = /[?:]\s*(['"])([^'"]*[a-zA-Z]{2,}[^'"]*)\1/g;
for (const m of line.matchAll(exprRegex)) {
const value = m[2];
if (!value.includes(' ') || CLASS_LIKE.test(value)) continue;
violations.push({
file: rel,
line: i + 1,
text: trimmed,
reason: `hardcoded expression string: "${value}"`,
});
}
}

return violations;
const seen = new Set<string>();
return violations.filter((v) => {
const id = `${v.line}:${v.reason.slice(v.reason.indexOf('"'))}`;
if (seen.has(id)) return false;
seen.add(id);
return true;
});
}

const files = findTsxFiles(SRC_DIR);
Expand Down
4 changes: 3 additions & 1 deletion src/components/Form/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as SelectPrimitive from '@radix-ui/react-select';
import { useTranslations } from 'next-intl';
import React, {
useEffect,
useLayoutEffect,
Expand Down Expand Up @@ -66,6 +67,7 @@ export const Dropdown = React.forwardRef<HTMLButtonElement, DropdownProps>(
},
forwardedRef,
) => {
const t = useTranslations('Dropdown');
const isMinimalVariant = variant === 'minimal';
const isDefaultVariant = variant === 'default';
const [open, setOpen] = useState(false);
Expand Down Expand Up @@ -457,7 +459,7 @@ export const Dropdown = React.forwardRef<HTMLButtonElement, DropdownProps>(
</>
) : (
<div className="flex h-12 items-center justify-center text-gray-500 text-sm">
{searchable && searchTerm ? 'No results found' : 'No options'}
{searchable && searchTerm ? t('noResults') : t('noOptions')}
</div>
)}
</SelectPrimitive.Viewport>
Expand Down
4 changes: 4 additions & 0 deletions src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
"loading": "Loading...",
"noResults": "No results found."
},
"Dropdown": {
"noResults": "No results found",
"noOptions": "No options"
},
"Inbox": {
"notifications": "Notifications",
"noNotifications": "No notifications yet",
Expand Down
4 changes: 4 additions & 0 deletions src/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
"loading": "読み込み中...",
"noResults": "結果が見つかりませんでした。"
},
"Dropdown": {
"noResults": "結果が見つかりませんでした",
"noOptions": "選択肢がありません"
},
"Inbox": {
"notifications": "受信ボックス",
"noNotifications": "通知はまだありません",
Expand Down
Loading