@geenius/i18n 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/.changeset/config.json +11 -0
  2. package/.github/CODEOWNERS +1 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +16 -0
  4. package/.github/ISSUE_TEMPLATE/feature_request.md +11 -0
  5. package/.github/PULL_REQUEST_TEMPLATE.md +10 -0
  6. package/.github/dependabot.yml +11 -0
  7. package/.github/workflows/ci.yml +23 -0
  8. package/.github/workflows/release.yml +29 -0
  9. package/.nvmrc +1 -0
  10. package/.project/ACCOUNT.yaml +4 -0
  11. package/.project/IDEAS.yaml +7 -0
  12. package/.project/PROJECT.yaml +11 -0
  13. package/.project/ROADMAP.yaml +15 -0
  14. package/CHANGELOG.md +8 -0
  15. package/CODE_OF_CONDUCT.md +16 -0
  16. package/CONTRIBUTING.md +26 -0
  17. package/LICENSE +2 -0
  18. package/README.md +1 -0
  19. package/SECURITY.md +15 -0
  20. package/SUPPORT.md +8 -0
  21. package/package.json +75 -0
  22. package/packages/convex/package.json +42 -0
  23. package/packages/convex/src/index.ts +3 -0
  24. package/packages/convex/src/mutations.ts +65 -0
  25. package/packages/convex/src/queries.ts +54 -0
  26. package/packages/convex/src/schema.ts +26 -0
  27. package/packages/convex/tsconfig.json +18 -0
  28. package/packages/convex/tsup.config.ts +17 -0
  29. package/packages/react/README.md +1 -0
  30. package/packages/react/package.json +51 -0
  31. package/packages/react/src/components/index.tsx +87 -0
  32. package/packages/react/src/hooks/index.ts +4 -0
  33. package/packages/react/src/hooks/useI18n.tsx +50 -0
  34. package/packages/react/src/hooks/useI18nAdmin.ts +12 -0
  35. package/packages/react/src/hooks/useLocaleDetect.ts +10 -0
  36. package/packages/react/src/hooks/useTranslations.ts +11 -0
  37. package/packages/react/src/index.tsx +8 -0
  38. package/packages/react/src/pages/I18nAdminPage.tsx +42 -0
  39. package/packages/react/src/pages/LocalePreviewPage.tsx +54 -0
  40. package/packages/react/src/pages/index.ts +2 -0
  41. package/packages/react/tsconfig.json +19 -0
  42. package/packages/react/tsup.config.ts +12 -0
  43. package/packages/react-css/README.md +1 -0
  44. package/packages/react-css/package.json +36 -0
  45. package/packages/react-css/src/components/index.tsx +66 -0
  46. package/packages/react-css/src/hooks/index.ts +4 -0
  47. package/packages/react-css/src/index.tsx +4 -0
  48. package/packages/react-css/src/pages/LocaleSettingsPage.tsx +74 -0
  49. package/packages/react-css/src/pages/TranslationsPage.tsx +98 -0
  50. package/packages/react-css/src/styles.css +210 -0
  51. package/packages/react-css/tsconfig.json +19 -0
  52. package/packages/react-css/tsup.config.ts +10 -0
  53. package/packages/shared/README.md +1 -0
  54. package/packages/shared/package.json +44 -0
  55. package/packages/shared/src/__tests__/i18n.test.ts +78 -0
  56. package/packages/shared/src/config.ts +344 -0
  57. package/packages/shared/src/index.ts +106 -0
  58. package/packages/shared/src/types.ts +51 -0
  59. package/packages/shared/tsconfig.json +18 -0
  60. package/packages/shared/tsup.config.ts +11 -0
  61. package/packages/shared/vitest.config.ts +4 -0
  62. package/packages/solidjs/README.md +1 -0
  63. package/packages/solidjs/package.json +47 -0
  64. package/packages/solidjs/src/components/LocaleCard.tsx +44 -0
  65. package/packages/solidjs/src/components/LocaleStatsCard.tsx +35 -0
  66. package/packages/solidjs/src/components/LocaleSwitcher.tsx +65 -0
  67. package/packages/solidjs/src/components/MissingKeyAlert.tsx +21 -0
  68. package/packages/solidjs/src/components/RTLWrapper.tsx +13 -0
  69. package/packages/solidjs/src/components/TranslationKeyRow.tsx +41 -0
  70. package/packages/solidjs/src/components/index.ts +6 -0
  71. package/packages/solidjs/src/index.tsx +8 -0
  72. package/packages/solidjs/src/pages/I18nAdminPage.tsx +188 -0
  73. package/packages/solidjs/src/pages/LocalePreviewPage.tsx +99 -0
  74. package/packages/solidjs/src/pages/index.ts +2 -0
  75. package/packages/solidjs/src/primitives/I18nProvider.tsx +56 -0
  76. package/packages/solidjs/src/primitives/createI18nAdmin.ts +7 -0
  77. package/packages/solidjs/src/primitives/createLocaleDetect.ts +8 -0
  78. package/packages/solidjs/src/primitives/createTranslations.ts +22 -0
  79. package/packages/solidjs/src/primitives/index.ts +4 -0
  80. package/packages/solidjs/tsconfig.json +20 -0
  81. package/packages/solidjs/tsup.config.ts +12 -0
  82. package/packages/solidjs-css/README.md +1 -0
  83. package/packages/solidjs-css/package.json +33 -0
  84. package/packages/solidjs-css/src/components/LocaleCard.tsx +45 -0
  85. package/packages/solidjs-css/src/components/LocaleStatsCard.tsx +43 -0
  86. package/packages/solidjs-css/src/components/LocaleSwitcher.tsx +51 -0
  87. package/packages/solidjs-css/src/components/MissingKeyAlert.tsx +24 -0
  88. package/packages/solidjs-css/src/components/RTLWrapper.tsx +16 -0
  89. package/packages/solidjs-css/src/components/TranslationKeyRow.tsx +47 -0
  90. package/packages/solidjs-css/src/components/index.ts +6 -0
  91. package/packages/solidjs-css/src/i18n.css +1322 -0
  92. package/packages/solidjs-css/src/index.tsx +3 -0
  93. package/packages/solidjs-css/src/pages/I18nAdminPage.tsx +134 -0
  94. package/packages/solidjs-css/src/pages/LocalePreviewPage.tsx +116 -0
  95. package/packages/solidjs-css/src/pages/index.ts +2 -0
  96. package/packages/solidjs-css/src/primitives/index.ts +1 -0
  97. package/packages/solidjs-css/tsconfig.json +20 -0
  98. package/packages/solidjs-css/tsup.config.bundled_dcjc4sct21j.mjs +18 -0
  99. package/packages/solidjs-css/tsup.config.ts +14 -0
  100. package/pnpm-workspace.yaml +2 -0
  101. package/tsconfig.json +23 -0
@@ -0,0 +1,45 @@
1
+ import { Show } from 'solid-js'
2
+ import type { Component } from 'solid-js'
3
+ import type { Locale } from '@geenius-i18n/shared'
4
+ import { LOCALE_INFO } from '@geenius-i18n/shared'
5
+
6
+ interface Props {
7
+ locale: Locale
8
+ coverage: number
9
+ isSelected: boolean
10
+ onSelect: (l: Locale) => void
11
+ }
12
+
13
+ export const LocaleCard: Component<Props> = (props) => {
14
+ const info = () => LOCALE_INFO[props.locale]
15
+ const barModifier = () =>
16
+ props.coverage >= 90 ? 'i18n__locale-card-bar-fill--complete'
17
+ : props.coverage >= 70 ? 'i18n__locale-card-bar-fill--partial'
18
+ : 'i18n__locale-card-bar-fill--low'
19
+
20
+ return (
21
+ <button
22
+ type="button"
23
+ class={`i18n__locale-card${props.isSelected ? ' i18n__locale-card--selected' : ''}`}
24
+ onClick={() => props.onSelect(props.locale)}
25
+ >
26
+ <div class="i18n__locale-card-header">
27
+ <span class="i18n__locale-card-flag">{info()?.flag}</span>
28
+ <div class="i18n__locale-card-info">
29
+ <span class="i18n__locale-card-name">{info()?.nativeName}</span>
30
+ <span class="i18n__locale-card-code">{info()?.name} — {props.locale.toUpperCase()}</span>
31
+ </div>
32
+ <Show when={info()?.direction === 'rtl'}>
33
+ <span class="i18n__locale-card-rtl">RTL</span>
34
+ </Show>
35
+ </div>
36
+ <div class="i18n__locale-card-bar">
37
+ <div
38
+ class={`i18n__locale-card-bar-fill ${barModifier()}`}
39
+ style={{ width: `${props.coverage}%` }}
40
+ />
41
+ </div>
42
+ <span class="i18n__locale-card-coverage">{props.coverage}%</span>
43
+ </button>
44
+ )
45
+ }
@@ -0,0 +1,43 @@
1
+ import { Show } from 'solid-js'
2
+ import type { Component } from 'solid-js'
3
+ import type { LocaleStat } from '@geenius-i18n/shared'
4
+ import { LOCALE_INFO } from '@geenius-i18n/shared'
5
+
6
+ interface Props {
7
+ stat: LocaleStat
8
+ }
9
+
10
+ export const LocaleStatsCard: Component<Props> = (props) => {
11
+ const info = () => LOCALE_INFO[props.stat.locale]
12
+ const barModifier = () =>
13
+ props.stat.coverage >= 90 ? 'i18n__stats-card-bar-fill--complete'
14
+ : props.stat.coverage >= 70 ? 'i18n__stats-card-bar-fill--partial'
15
+ : 'i18n__stats-card-bar-fill--low'
16
+
17
+ return (
18
+ <div class="i18n__stats-card">
19
+ <div class="i18n__stats-card-header">
20
+ <span class="i18n__stats-card-flag">{info()?.flag}</span>
21
+ <span class="i18n__stats-card-locale">{info()?.nativeName}</span>
22
+ </div>
23
+ <div class="i18n__stats-card-coverage">
24
+ <span class="i18n__stats-card-keys">{props.stat.totalKeys} keys</span>
25
+ <span class="i18n__stats-card-percent">{props.stat.coverage}%</span>
26
+ </div>
27
+ <div class="i18n__stats-card-bar">
28
+ <div
29
+ class={`i18n__stats-card-bar-fill ${barModifier()}`}
30
+ style={{ width: `${props.stat.coverage}%` }}
31
+ />
32
+ </div>
33
+ <div class="i18n__stats-card-counts">
34
+ <Show when={props.stat.missingKeys > 0}>
35
+ <span class="i18n__stats-card-missing">{props.stat.missingKeys} missing</span>
36
+ </Show>
37
+ <Show when={props.stat.missingKeys === 0}>
38
+ <span class="i18n__stats-card-complete">Complete</span>
39
+ </Show>
40
+ </div>
41
+ </div>
42
+ )
43
+ }
@@ -0,0 +1,51 @@
1
+ import { createSignal, Show, For } from 'solid-js'
2
+ import type { Component } from 'solid-js'
3
+ import type { Locale } from '@geenius-i18n/shared'
4
+ import { LOCALE_INFO } from '@geenius-i18n/shared'
5
+
6
+ interface Props {
7
+ locales: Locale[]
8
+ current: Locale
9
+ onChange: (l: Locale) => void
10
+ }
11
+
12
+ export const LocaleSwitcher: Component<Props> = (props) => {
13
+ const [open, setOpen] = createSignal(false)
14
+
15
+ return (
16
+ <div class="i18n__locale-switcher">
17
+ <button
18
+ type="button"
19
+ class="i18n__locale-switcher-trigger"
20
+ onClick={() => setOpen((o) => !o)}
21
+ >
22
+ <span class="i18n__locale-switcher-flag">{LOCALE_INFO[props.current]?.flag}</span>
23
+ <span class="i18n__locale-switcher-label">{LOCALE_INFO[props.current]?.nativeName}</span>
24
+ <span class="i18n__locale-switcher-arrow">▾</span>
25
+ </button>
26
+
27
+ <Show when={open()}>
28
+ <div class="i18n__locale-switcher-dropdown">
29
+ <For each={props.locales}>
30
+ {(locale) => {
31
+ const info = LOCALE_INFO[locale]
32
+ return (
33
+ <button
34
+ type="button"
35
+ class={`i18n__locale-switcher-option${locale === props.current ? ' i18n__locale-switcher-option--active' : ''}`}
36
+ onClick={() => { props.onChange(locale); setOpen(false) }}
37
+ >
38
+ <span class="i18n__locale-switcher-option-flag">{info?.flag}</span>
39
+ <span class="i18n__locale-switcher-option-name">{info?.nativeName}</span>
40
+ <Show when={info?.direction === 'rtl'}>
41
+ <span class="i18n__locale-switcher-option-rtl">RTL</span>
42
+ </Show>
43
+ </button>
44
+ )
45
+ }}
46
+ </For>
47
+ </div>
48
+ </Show>
49
+ </div>
50
+ )
51
+ }
@@ -0,0 +1,24 @@
1
+ import { Show } from 'solid-js'
2
+ import type { Component } from 'solid-js'
3
+ import type { Locale } from '@geenius-i18n/shared'
4
+ import { LOCALE_INFO } from '@geenius-i18n/shared'
5
+
6
+ interface Props {
7
+ count: number
8
+ locale: Locale
9
+ }
10
+
11
+ export const MissingKeyAlert: Component<Props> = (props) => {
12
+ return (
13
+ <Show when={props.count > 0}>
14
+ <div class="i18n__missing-alert">
15
+ <span class="i18n__missing-alert-icon">⚠️</span>
16
+ <span class="i18n__missing-alert-text">
17
+ <span class="i18n__missing-alert-count">{props.count}</span>
18
+ {' '}missing key{props.count > 1 ? 's' : ''} for{' '}
19
+ <strong>{LOCALE_INFO[props.locale]?.name}</strong>
20
+ </span>
21
+ </div>
22
+ </Show>
23
+ )
24
+ }
@@ -0,0 +1,16 @@
1
+ import type { ParentComponent } from 'solid-js'
2
+ import type { Locale } from '@geenius-i18n/shared'
3
+ import { LOCALE_INFO } from '@geenius-i18n/shared'
4
+
5
+ export const RTLWrapper: ParentComponent<{ locale?: Locale }> = (props) => {
6
+ const dir = () => props.locale ? LOCALE_INFO[props.locale]?.direction ?? 'ltr' : 'ltr'
7
+
8
+ return (
9
+ <div
10
+ class={`i18n__rtl-wrapper i18n__rtl-wrapper--${dir()}`}
11
+ dir={dir()}
12
+ >
13
+ {props.children}
14
+ </div>
15
+ )
16
+ }
@@ -0,0 +1,47 @@
1
+ import { Show } from 'solid-js'
2
+ import type { Component } from 'solid-js'
3
+ import type { Locale } from '@geenius-i18n/shared'
4
+
5
+ interface Props {
6
+ translationKey: string
7
+ value: string
8
+ locale: Locale
9
+ namespace?: string
10
+ onEdit?: (key: string, value: string) => void
11
+ onDelete?: (key: string) => void
12
+ }
13
+
14
+ export const TranslationKeyRow: Component<Props> = (props) => {
15
+ return (
16
+ <div class="i18n__key-row">
17
+ <div class="i18n__key-row-key">{props.translationKey}</div>
18
+ <div class="i18n__key-row-value">{props.value}</div>
19
+ <div class="i18n__key-row-locale">
20
+ <span class="i18n__key-row-locale-badge">{props.locale.toUpperCase()}</span>
21
+ <Show when={props.namespace}>
22
+ <span class="i18n__key-row-namespace">{props.namespace}</span>
23
+ </Show>
24
+ </div>
25
+ <div class="i18n__key-row-actions">
26
+ <Show when={props.onEdit}>
27
+ <button
28
+ type="button"
29
+ class="i18n__key-row-btn i18n__key-row-btn--edit"
30
+ onClick={() => props.onEdit?.(props.translationKey, props.value)}
31
+ >
32
+ Edit
33
+ </button>
34
+ </Show>
35
+ <Show when={props.onDelete}>
36
+ <button
37
+ type="button"
38
+ class="i18n__key-row-btn i18n__key-row-btn--delete"
39
+ onClick={() => props.onDelete?.(props.translationKey)}
40
+ >
41
+ Delete
42
+ </button>
43
+ </Show>
44
+ </div>
45
+ </div>
46
+ )
47
+ }
@@ -0,0 +1,6 @@
1
+ export { LocaleSwitcher } from './LocaleSwitcher'
2
+ export { RTLWrapper } from './RTLWrapper'
3
+ export { LocaleStatsCard } from './LocaleStatsCard'
4
+ export { MissingKeyAlert } from './MissingKeyAlert'
5
+ export { TranslationKeyRow } from './TranslationKeyRow'
6
+ export { LocaleCard } from './LocaleCard'