docs-i18n 0.8.1 → 0.8.3

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 (88) hide show
  1. package/admin/dist/server/server.js +32 -32
  2. package/package.json +1 -1
  3. package/template/app/routes/$lang.$project.$version.docs.$.tsx +2 -1
  4. package/template/app/routes/$lang.$project.$version.docs.framework.$framework.$.tsx +2 -0
  5. package/template/app/routes/$lang.$project.$version.docs.tsx +2 -1
  6. package/template/app/routes/$lang.$project.docs.$.tsx +2 -1
  7. package/template/app/routes/$lang.$project.docs.tsx +2 -1
  8. package/template/app/routes/$lang.docs.$.tsx +2 -1
  9. package/template/app/routes/$lang.docs.framework.$framework.$.tsx +2 -0
  10. package/template/app/routes/$lang.docs.tsx +2 -1
  11. package/template/app/utils/content-loader.ts +13 -2
  12. package/template/app/utils/docs.server.ts +17 -15
  13. package/template/content/blog/en/announcing-query-v5.md +110 -0
  14. package/template/content/blog/en/hello-world.md +26 -0
  15. package/template/content/blog/en/i18n-best-practices.md +57 -0
  16. package/template/content/blog/en/react-query-vs-swr.md +100 -0
  17. package/template/content/blog/en/state-management-2024.md +143 -0
  18. package/template/content/blog/en/tanstack-router-1.0.md +121 -0
  19. package/template/content/blog/ja/announcing-query-v5.md +110 -0
  20. package/template/content/blog/ja/hello-world.md +26 -0
  21. package/template/content/blog/zh-hans/announcing-query-v5.md +93 -0
  22. package/template/content/blog/zh-hans/hello-world.md +26 -0
  23. package/template/content/docs-i18n/docs.config.json +25 -0
  24. package/template/content/docs-i18n/en/architecture.md +335 -0
  25. package/template/content/docs-i18n/en/cli.md +13 -1
  26. package/template/content/docs-i18n/en/configuration.md +350 -0
  27. package/template/content/docs-i18n/en/deployment.md +222 -0
  28. package/template/content/docs-i18n/en/getting-started.md +189 -0
  29. package/template/content/docs.config.json +25 -0
  30. package/template/content/en/admin.md +151 -0
  31. package/template/content/en/architecture.md +222 -0
  32. package/template/content/en/cli.md +269 -0
  33. package/template/content/en/configuration.md +331 -0
  34. package/template/content/en/deployment.md +209 -0
  35. package/template/content/en/getting-started.md +168 -0
  36. package/template/content/form/docs.config.json +18 -0
  37. package/template/content/form/en/guides/validation.md +175 -0
  38. package/template/content/form/en/installation.md +63 -0
  39. package/template/content/form/en/overview.md +71 -0
  40. package/template/content/form/en/quick-start.md +121 -0
  41. package/template/content/form/ja/installation.md +63 -0
  42. package/template/content/form/ja/overview.md +71 -0
  43. package/template/content/form/zh-hans/installation.md +63 -0
  44. package/template/content/form/zh-hans/overview.md +71 -0
  45. package/template/content/query/docs.config.json +32 -0
  46. package/template/content/query/en/guides/mutations.md +126 -0
  47. package/template/content/query/en/guides/pagination.md +98 -0
  48. package/template/content/query/en/guides/queries.md +120 -0
  49. package/template/content/query/en/installation.md +78 -0
  50. package/template/content/query/en/overview.md +72 -0
  51. package/template/content/query/en/quick-start.md +108 -0
  52. package/template/content/query/ja/installation.md +78 -0
  53. package/template/content/query/ja/overview.md +72 -0
  54. package/template/content/query/zh-hans/guides/mutations.md +126 -0
  55. package/template/content/query/zh-hans/guides/pagination.md +98 -0
  56. package/template/content/query/zh-hans/guides/queries.md +120 -0
  57. package/template/content/query/zh-hans/installation.md +95 -0
  58. package/template/content/query/zh-hans/overview.md +72 -0
  59. package/template/content/query/zh-hans/quick-start.md +108 -0
  60. package/template/content/router/docs.config.json +18 -0
  61. package/template/content/router/en/guides/routing-concepts.md +131 -0
  62. package/template/content/router/en/installation.md +57 -0
  63. package/template/content/router/en/overview.md +74 -0
  64. package/template/content/router/en/quick-start.md +88 -0
  65. package/template/content/router/ja/installation.md +57 -0
  66. package/template/content/router/ja/overview.md +78 -0
  67. package/template/content/router/zh-hans/guides/routing-concepts.md +131 -0
  68. package/template/content/router/zh-hans/installation.md +57 -0
  69. package/template/content/router/zh-hans/overview.md +81 -0
  70. package/template/content/router/zh-hans/quick-start.md +88 -0
  71. package/template/content/table/docs.config.json +18 -0
  72. package/template/content/table/en/guides/column-definitions.md +135 -0
  73. package/template/content/table/en/installation.md +56 -0
  74. package/template/content/table/en/overview.md +79 -0
  75. package/template/content/table/en/quick-start.md +112 -0
  76. package/template/content/table/ja/installation.md +56 -0
  77. package/template/content/table/ja/overview.md +79 -0
  78. package/template/content/table/zh-hans/installation.md +56 -0
  79. package/template/content/table/zh-hans/overview.md +79 -0
  80. package/template/content/virtual/docs.config.json +18 -0
  81. package/template/content/virtual/en/guides/dynamic-sizing.md +129 -0
  82. package/template/content/virtual/en/installation.md +57 -0
  83. package/template/content/virtual/en/overview.md +74 -0
  84. package/template/content/virtual/en/quick-start.md +114 -0
  85. package/template/content/virtual/ja/installation.md +57 -0
  86. package/template/content/virtual/ja/overview.md +74 -0
  87. package/template/content/virtual/zh-hans/installation.md +57 -0
  88. package/template/content/virtual/zh-hans/overview.md +74 -0
@@ -15556,29 +15556,21 @@ async function getStartManifest(matchedRoutes) {
15556
15556
  //#endregion
15557
15557
  //#region \0#tanstack-start-server-fn-resolver
15558
15558
  var manifest = {
15559
- "4e218d79545765572808c7eab33b7663d4496209c15406d0b449366905b6b83f": {
15560
- functionName: "fetchStatus_createServerFn_handler",
15561
- importer: () => import("./assets/status-CM7Azp4n.js")
15562
- },
15563
- "843cd8b59095708a5ae78198708db9850f89fd3dd3830ab236f0bd924417692f": {
15564
- functionName: "fetchFileCoverage_createServerFn_handler",
15565
- importer: () => import("./assets/status-CM7Azp4n.js")
15566
- },
15567
- "e1e7281e45375c67dbe408c58452e7482b139da60e9e361615553227dce95ee0": {
15568
- functionName: "fetchFileBlocks_createServerFn_handler",
15569
- importer: () => import("./assets/status-CM7Azp4n.js")
15559
+ "a3d81974aeece150d4b02be5b91590b8187442ebea56be4a89dcbf053626d22b": {
15560
+ functionName: "fetchVersion_createServerFn_handler",
15561
+ importer: () => import("./assets/misc-y6t3-UOP.js")
15570
15562
  },
15571
- "e1d13d8602339a95f559345ccfc82e9f843dd375ce8e9f580637c241e7e44774": {
15572
- functionName: "deleteCacheEntry_createServerFn_handler",
15573
- importer: () => import("./assets/status-CM7Azp4n.js")
15563
+ "3bf4ba50ca8ccc3c8c60d8f2e53307a320940d68c478df494552066904c5cd74": {
15564
+ functionName: "fetchLlmConfig_createServerFn_handler",
15565
+ importer: () => import("./assets/misc-y6t3-UOP.js")
15574
15566
  },
15575
- "1d8e3916f992485c62e62c3693083850b773fdff4ec54277de5a01eb98dab664": {
15576
- functionName: "rescanVersion_createServerFn_handler",
15577
- importer: () => import("./assets/status-CM7Azp4n.js")
15567
+ "e0b4116f6b2c8d096830102e36458acf9c616a056fcdddda956a4d66984ef58c": {
15568
+ functionName: "fetchConfig_createServerFn_handler",
15569
+ importer: () => import("./assets/misc-y6t3-UOP.js")
15578
15570
  },
15579
- "5080dc3f2f2309ec6981b94c431969637130c657e8a1dfb10400b4614eecc1ea": {
15580
- functionName: "fetchModels_createServerFn_handler",
15581
- importer: () => import("./assets/models-YNa3F3nn.js")
15571
+ "a054a04356fe9987891efee8b7a11cd2dedb00f6b2e8f26d1c642e001e553d53": {
15572
+ functionName: "openFile_createServerFn_handler",
15573
+ importer: () => import("./assets/misc-y6t3-UOP.js")
15582
15574
  },
15583
15575
  "421de02ce39dde6e27cf4689e837ec072cbd01e63f8cdd5c2a3f42f0bd5ca613": {
15584
15576
  functionName: "fetchJobs_createServerFn_handler",
@@ -15596,21 +15588,29 @@ var manifest = {
15596
15588
  functionName: "deleteJob_createServerFn_handler",
15597
15589
  importer: () => import("./assets/jobs-FXffC7LH.js")
15598
15590
  },
15599
- "a3d81974aeece150d4b02be5b91590b8187442ebea56be4a89dcbf053626d22b": {
15600
- functionName: "fetchVersion_createServerFn_handler",
15601
- importer: () => import("./assets/misc-y6t3-UOP.js")
15591
+ "4e218d79545765572808c7eab33b7663d4496209c15406d0b449366905b6b83f": {
15592
+ functionName: "fetchStatus_createServerFn_handler",
15593
+ importer: () => import("./assets/status-CM7Azp4n.js")
15602
15594
  },
15603
- "3bf4ba50ca8ccc3c8c60d8f2e53307a320940d68c478df494552066904c5cd74": {
15604
- functionName: "fetchLlmConfig_createServerFn_handler",
15605
- importer: () => import("./assets/misc-y6t3-UOP.js")
15595
+ "843cd8b59095708a5ae78198708db9850f89fd3dd3830ab236f0bd924417692f": {
15596
+ functionName: "fetchFileCoverage_createServerFn_handler",
15597
+ importer: () => import("./assets/status-CM7Azp4n.js")
15606
15598
  },
15607
- "e0b4116f6b2c8d096830102e36458acf9c616a056fcdddda956a4d66984ef58c": {
15608
- functionName: "fetchConfig_createServerFn_handler",
15609
- importer: () => import("./assets/misc-y6t3-UOP.js")
15599
+ "e1e7281e45375c67dbe408c58452e7482b139da60e9e361615553227dce95ee0": {
15600
+ functionName: "fetchFileBlocks_createServerFn_handler",
15601
+ importer: () => import("./assets/status-CM7Azp4n.js")
15610
15602
  },
15611
- "a054a04356fe9987891efee8b7a11cd2dedb00f6b2e8f26d1c642e001e553d53": {
15612
- functionName: "openFile_createServerFn_handler",
15613
- importer: () => import("./assets/misc-y6t3-UOP.js")
15603
+ "e1d13d8602339a95f559345ccfc82e9f843dd375ce8e9f580637c241e7e44774": {
15604
+ functionName: "deleteCacheEntry_createServerFn_handler",
15605
+ importer: () => import("./assets/status-CM7Azp4n.js")
15606
+ },
15607
+ "1d8e3916f992485c62e62c3693083850b773fdff4ec54277de5a01eb98dab664": {
15608
+ functionName: "rescanVersion_createServerFn_handler",
15609
+ importer: () => import("./assets/status-CM7Azp4n.js")
15610
+ },
15611
+ "5080dc3f2f2309ec6981b94c431969637130c657e8a1dfb10400b4614eecc1ea": {
15612
+ functionName: "fetchModels_createServerFn_handler",
15613
+ importer: () => import("./assets/models-YNa3F3nn.js")
15614
15614
  }
15615
15615
  };
15616
15616
  async function getServerFnById(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docs-i18n",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
4
4
  "description": "Universal documentation translation engine — parse, translate, cache, assemble, manage.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -15,7 +15,8 @@ const fetchDoc = createServerFn({ method: 'GET' })
15
15
  )
16
16
  .handler(async ({ data }) => {
17
17
  const { loadDoc } = await import('~/utils/docs.server')
18
- return loadDoc(data.project, data.version, data.lang, data.slug)
18
+ const projectConfig = findProject(data.project)
19
+ return loadDoc(data.project, data.version, data.lang, data.slug, projectConfig)
19
20
  })
20
21
 
21
22
  export const Route = createFileRoute('/$lang/$project/$version/docs/$')({
@@ -19,11 +19,13 @@ const fetchFrameworkDoc = createServerFn({ method: 'GET' })
19
19
  )
20
20
  .handler(async ({ data }) => {
21
21
  const { loadDoc } = await import('~/utils/docs.server')
22
+ const projectConfig = findProject(data.project)
22
23
  return loadDoc(
23
24
  data.project,
24
25
  data.version,
25
26
  data.lang,
26
27
  `framework/${data.framework}/${data.slug}`,
28
+ projectConfig,
27
29
  )
28
30
  })
29
31
 
@@ -13,7 +13,8 @@ const fetchDocsConfig = createServerFn({ method: 'GET' })
13
13
  .inputValidator((data: { project: string; version: string }) => data)
14
14
  .handler(async ({ data }) => {
15
15
  const { loadDocsConfig } = await import('~/utils/docs.server')
16
- return loadDocsConfig(data.project, data.version)
16
+ const projectConfig = findProject(data.project)
17
+ return loadDocsConfig(data.project, data.version, projectConfig)
17
18
  })
18
19
 
19
20
  export const Route = createFileRoute('/$lang/$project/$version/docs')({
@@ -13,7 +13,8 @@ const fetchDoc = createServerFn({ method: 'GET' })
13
13
  )
14
14
  .handler(async ({ data }) => {
15
15
  const { loadDoc } = await import('~/utils/docs.server')
16
- return loadDoc(data.project, data.version, data.lang, data.slug)
16
+ const projectConfig = findProject(data.project)
17
+ return loadDoc(data.project, data.version, data.lang, data.slug, projectConfig)
17
18
  })
18
19
 
19
20
  export const Route = createFileRoute('/$lang/$project/docs/$')({
@@ -13,7 +13,8 @@ const fetchDocsConfig = createServerFn({ method: 'GET' })
13
13
  .inputValidator((data: { project: string; version: string }) => data)
14
14
  .handler(async ({ data }) => {
15
15
  const { loadDocsConfig } = await import('~/utils/docs.server')
16
- return loadDocsConfig(data.project, data.version)
16
+ const projectConfig = findProject(data.project)
17
+ return loadDocsConfig(data.project, data.version, projectConfig)
17
18
  })
18
19
 
19
20
  export const Route = createFileRoute('/$lang/$project/docs')({
@@ -13,7 +13,8 @@ const fetchDoc = createServerFn({ method: 'GET' })
13
13
  )
14
14
  .handler(async ({ data }) => {
15
15
  const { loadDoc } = await import('~/utils/docs.server')
16
- return loadDoc(data.project, data.version, data.lang, data.slug)
16
+ const projectConfig = getSingleProject()
17
+ return loadDoc(data.project, data.version, data.lang, data.slug, projectConfig)
17
18
  })
18
19
 
19
20
  export const Route = createFileRoute('/$lang/docs/$')({
@@ -19,11 +19,13 @@ const fetchFrameworkDoc = createServerFn({ method: 'GET' })
19
19
  )
20
20
  .handler(async ({ data }) => {
21
21
  const { loadDoc } = await import('~/utils/docs.server')
22
+ const projectConfig = getSingleProject()
22
23
  return loadDoc(
23
24
  data.project,
24
25
  data.version,
25
26
  data.lang,
26
27
  `framework/${data.framework}/${data.slug}`,
28
+ projectConfig,
27
29
  )
28
30
  })
29
31
 
@@ -15,7 +15,8 @@ const fetchDocsConfig = createServerFn({ method: 'GET' })
15
15
  .inputValidator((data: { project: string; version: string }) => data)
16
16
  .handler(async ({ data }) => {
17
17
  const { loadDocsConfig } = await import('~/utils/docs.server')
18
- return loadDocsConfig(data.project, data.version)
18
+ const projectConfig = getSingleProject()
19
+ return loadDocsConfig(data.project, data.version, projectConfig)
19
20
  })
20
21
 
21
22
  export const Route = createFileRoute('/$lang/docs')({
@@ -64,6 +64,7 @@ function getTranslationCache(projectRoot: string): TranslationCache | null {
64
64
 
65
65
  export function createFsLoader(
66
66
  projectRoot: string,
67
+ docsRoot = 'content',
67
68
  urlMapper?: (filePath: string) => string,
68
69
  ): ContentLoader {
69
70
  /** Supported markdown extensions, in priority order. */
@@ -79,10 +80,20 @@ export function createFsLoader(
79
80
  lang: string,
80
81
  slug: string,
81
82
  ): { raw: string; filePath: string } | null {
83
+ // Resolve content base directory using docsRoot from site config.
84
+ // docsRoot encodes the project-specific path (e.g. 'content/query', 'content/docs').
85
+ // Convention: no /en/ subdir — English source files live directly under version/.
86
+ // Non-English comes from .cache/ (translation assembly).
82
87
  const baseDirs = [
88
+ resolve(projectRoot, docsRoot, version),
89
+ resolve(projectRoot, docsRoot),
90
+ // Fallback: try content/{project}/{version} pattern
91
+ resolve(projectRoot, 'content', project, version),
92
+ resolve(projectRoot, 'content', version),
93
+ // Legacy: with lang subdir
83
94
  resolve(projectRoot, 'content', project, version, lang),
84
- resolve(projectRoot, 'content', project, lang),
85
- resolve(projectRoot, 'content', lang),
95
+ resolve(projectRoot, docsRoot, version, lang),
96
+ resolve(projectRoot, docsRoot, lang),
86
97
  ]
87
98
 
88
99
  if (!urlMapper) {
@@ -62,7 +62,7 @@ export function setContentLoader(loader: ContentLoader) {
62
62
 
63
63
  /**
64
64
  * Load a document with i18n fallback.
65
- * When projectConfig has urlMapper, creates a mapper-aware loader.
65
+ * Uses docsRoot from projectConfig to resolve content paths.
66
66
  */
67
67
  export async function loadDoc(
68
68
  project: string,
@@ -71,11 +71,9 @@ export async function loadDoc(
71
71
  slug: string,
72
72
  projectConfig?: ProjectConfig,
73
73
  ): Promise<LoadedDoc> {
74
- if (projectConfig?.urlMapper) {
75
- const loader = createFsLoader(getProjectRoot(), projectConfig.urlMapper)
76
- return loader.loadDoc(project, version, lang, slug)
77
- }
78
- return getLoader().loadDoc(project, version, lang, slug)
74
+ const docsRoot = projectConfig?.docsRoot || 'content'
75
+ const loader = createFsLoader(getProjectRoot(), docsRoot, projectConfig?.urlMapper)
76
+ return loader.loadDoc(project, version, lang, slug)
79
77
  }
80
78
 
81
79
  /**
@@ -91,11 +89,13 @@ export async function loadDocsConfig(
91
89
  return loadFilesystemSidebar(project, version, projectConfig)
92
90
  }
93
91
 
94
- const config = await getLoader().loadDocsConfig(project, version)
92
+ const docsRoot = projectConfig?.docsRoot || 'content'
93
+ const loader = createFsLoader(getProjectRoot(), docsRoot)
94
+ const config = await loader.loadDocsConfig(project, version)
95
95
  if (config) return config
96
96
 
97
97
  // Auto-scan fallback (filesystem only)
98
- return autoScanDocs(getProjectRoot(), project, version)
98
+ return autoScanDocs(getProjectRoot(), docsRoot, project, version)
99
99
  }
100
100
 
101
101
  /** Generate sidebar from filesystem using numeric prefix ordering. */
@@ -105,10 +105,11 @@ function loadFilesystemSidebar(
105
105
  projectConfig: ProjectConfig,
106
106
  ): DocsConfig {
107
107
  const root = getProjectRoot()
108
+ const docsRoot = projectConfig.docsRoot || 'content'
108
109
  const candidates = [
109
- resolve(root, 'content', project, version, 'en'),
110
- resolve(root, 'content', project, 'en'),
111
- resolve(root, 'content', 'en'),
110
+ resolve(root, docsRoot, version),
111
+ resolve(root, docsRoot),
112
+ resolve(root, 'content', project, version),
112
113
  ]
113
114
  for (const dir of candidates) {
114
115
  if (existsSync(dir) && statSync(dir).isDirectory()) {
@@ -120,17 +121,18 @@ function loadFilesystemSidebar(
120
121
  }
121
122
 
122
123
  /**
123
- * Auto-generate sidebar config by scanning .md files in the content directory.
124
+ * Auto-generate sidebar config by scanning .md/.mdx files in the content directory.
124
125
  */
125
126
  function autoScanDocs(
126
127
  root: string,
128
+ docsRoot: string,
127
129
  project: string,
128
130
  version: string,
129
131
  ): DocsConfig {
130
132
  const candidates = [
131
- resolve(root, 'content', project, version, 'en'),
132
- resolve(root, 'content', project, 'en'),
133
- resolve(root, 'content', 'en'),
133
+ resolve(root, docsRoot, version),
134
+ resolve(root, docsRoot),
135
+ resolve(root, 'content', project, version),
134
136
  ]
135
137
 
136
138
  for (const dir of candidates) {
@@ -0,0 +1,110 @@
1
+ ---
2
+ title: "Announcing TanStack Query v5"
3
+ published: "2024-10-01"
4
+ excerpt: "TanStack Query v5 is here with a simplified API, better TypeScript support, improved devtools, and a smaller bundle size. Here is everything you need to know."
5
+ authors:
6
+ - "Tanner Linsley"
7
+ - "Dominik Dorfmeister"
8
+ ---
9
+
10
+ We are thrilled to announce the release of TanStack Query v5! This release represents months of work from the community and brings significant improvements across the board.
11
+
12
+ ## What's New
13
+
14
+ ### Simplified API
15
+
16
+ The most visible change in v5 is the simplified API. We have removed the object syntax overloads in favor of a single, consistent object syntax for all hooks:
17
+
18
+ ```tsx
19
+ // v4 — multiple overloads
20
+ useQuery(['todos'], fetchTodos)
21
+ useQuery(['todos'], fetchTodos, { staleTime: 5000 })
22
+ useQuery({ queryKey: ['todos'], queryFn: fetchTodos })
23
+
24
+ // v5 — single consistent API
25
+ useQuery({
26
+ queryKey: ['todos'],
27
+ queryFn: fetchTodos,
28
+ staleTime: 5000,
29
+ })
30
+ ```
31
+
32
+ This makes the API easier to learn and provides better TypeScript inference.
33
+
34
+ ### Better TypeScript Support
35
+
36
+ v5 includes major TypeScript improvements:
37
+
38
+ - **Strict query key typing** — query keys are now strictly typed throughout
39
+ - **Inferred return types** — `useQuery` correctly infers the return type from `queryFn`
40
+ - **Type-safe error handling** — errors are properly typed with the new `Error` generic parameter
41
+
42
+ ```tsx
43
+ // Error type is now inferred and type-safe
44
+ const { data, error } = useQuery({
45
+ queryKey: ['user', userId],
46
+ queryFn: async () => {
47
+ const res = await fetch(`/api/users/${userId}`)
48
+ if (!res.ok) throw new ApiError(res.status, await res.text())
49
+ return res.json() as Promise<User>
50
+ },
51
+ })
52
+
53
+ // error is typed as ApiError | null
54
+ if (error) {
55
+ console.log(error.status) // TypeScript knows this exists
56
+ }
57
+ ```
58
+
59
+ ### New Devtools
60
+
61
+ The devtools have been completely rewritten with a new design, better performance, and new features:
62
+
63
+ - **Query timeline** — visualize query fetches over time
64
+ - **Mutation inspector** — inspect mutation state and variables
65
+ - **Cache explorer** — browse the entire query cache
66
+ - **Online/offline toggle** — test offline behavior
67
+
68
+ ### Smaller Bundle Size
69
+
70
+ We have reduced the core bundle size by approximately 20% through tree-shaking improvements and removing deprecated APIs.
71
+
72
+ | Package | v4 | v5 | Change |
73
+ |---|---|---|---|
74
+ | `@tanstack/react-query` | 12.4 KB | 9.8 KB | -21% |
75
+ | `@tanstack/query-core` | 10.1 KB | 8.2 KB | -19% |
76
+
77
+ ## Breaking Changes
78
+
79
+ > [!WARNING]
80
+ > v5 includes several breaking changes. Please review the full [migration guide](/en/query/docs/guides/migration-v5) before upgrading.
81
+
82
+ Key breaking changes:
83
+
84
+ 1. **Removed overloaded signatures** — all hooks now use object-only syntax
85
+ 2. **Renamed `cacheTime` to `gcTime`** — better reflects its purpose (garbage collection time)
86
+ 3. **`status: 'loading'` renamed to `status: 'pending'`** — aligns with Promise terminology
87
+ 4. **Removed `keepPreviousData`** — replaced with `placeholderData: keepPreviousData` (import from query core)
88
+ 5. **Minimum TypeScript version is now 4.7**
89
+
90
+ ## Migration
91
+
92
+ We have built a codemod to automate most of the migration:
93
+
94
+ ```bash
95
+ npx @tanstack/query-codemod v5 ./src
96
+ ```
97
+
98
+ This will handle the most common transformations automatically. Review the changes and test thoroughly.
99
+
100
+ ## Thank You
101
+
102
+ Thank you to the 100+ contributors who made this release possible. TanStack Query v5 would not exist without the incredible open source community.
103
+
104
+ Get started with v5 today:
105
+
106
+ ```bash
107
+ npm install @tanstack/react-query@latest
108
+ ```
109
+
110
+ Happy querying!
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: "Hello World: Introducing docs-i18n Blog"
3
+ published: "2024-01-15"
4
+ excerpt: "Welcome to the docs-i18n blog! We will share updates, tutorials, and best practices for internationalizing your documentation."
5
+ authors:
6
+ - "docs-i18n Team"
7
+ ---
8
+
9
+ Welcome to the docs-i18n blog! This is where we will share project updates, tutorials, and best practices for documentation internationalization.
10
+
11
+ ## What is docs-i18n?
12
+
13
+ docs-i18n is a universal documentation translation engine that makes it easy to maintain multilingual documentation sites. It provides:
14
+
15
+ - **Filesystem-based content loading** with i18n fallback
16
+ - **Markdown rendering** with syntax highlighting and framework-aware content
17
+ - **Admin interface** for managing translations
18
+ - **CLI tools** for automating translation workflows
19
+
20
+ ## Getting Started
21
+
22
+ Check out our [getting started guide](/en/getting-started) to learn how to set up docs-i18n for your project.
23
+
24
+ ## Stay Tuned
25
+
26
+ We have exciting features planned for upcoming releases. Follow this blog for the latest updates!
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: "Best Practices for Documentation i18n"
3
+ published: "2024-02-10"
4
+ excerpt: "Learn the key principles and patterns for effectively internationalizing your documentation, from content structure to translation workflows."
5
+ authors:
6
+ - "docs-i18n Team"
7
+ ---
8
+
9
+ Internationalizing documentation is more than just translating text. Here are the best practices we have learned from building docs-i18n.
10
+
11
+ ## Structure Content for Translation
12
+
13
+ ### Use English as Source of Truth
14
+
15
+ Keep your English content as the canonical source. All translations derive from it, and the system falls back to English when a translation is missing.
16
+
17
+ ### Separate Content from Presentation
18
+
19
+ Store your documentation as plain markdown files organized by locale:
20
+
21
+ ```
22
+ content/
23
+ blog/
24
+ en/
25
+ my-post.md
26
+ zh-hans/
27
+ my-post.md
28
+ ja/
29
+ my-post.md
30
+ ```
31
+
32
+ ### Use Frontmatter for Metadata
33
+
34
+ Each document should have frontmatter with at least a `title` field. For blog posts, include `published`, `excerpt`, and `authors`.
35
+
36
+ ## Translation Workflow
37
+
38
+ ### Start with High-Impact Pages
39
+
40
+ Not all pages need translation at once. Prioritize:
41
+
42
+ 1. Getting started guides
43
+ 2. Core concept documentation
44
+ 3. API reference
45
+ 4. Blog posts and announcements
46
+
47
+ ### Leverage Fallback Content
48
+
49
+ docs-i18n automatically falls back to English when a translation is missing. This means your site works for all locales immediately — translations improve it incrementally.
50
+
51
+ ### Keep Translations in Sync
52
+
53
+ When the English source changes, translations may become outdated. Use the docs-i18n admin interface to track which translations need updating.
54
+
55
+ ## Conclusion
56
+
57
+ Good documentation internationalization is an ongoing process. Start simple, prioritize high-impact content, and iterate.
@@ -0,0 +1,100 @@
1
+ ---
2
+ title: "TanStack Query vs SWR: A Detailed Comparison"
3
+ published: "2024-06-15"
4
+ excerpt: "An honest, detailed comparison of TanStack Query and SWR — two of the most popular data fetching libraries in the React ecosystem."
5
+ authors:
6
+ - "docs-i18n Team"
7
+ ---
8
+
9
+ Choosing a data fetching library is an important architectural decision. TanStack Query and SWR are the two most popular options in the React ecosystem. Here is an honest comparison to help you decide.
10
+
11
+ ## Overview
12
+
13
+ Both libraries solve the same core problem: managing server state in React applications. They both provide hooks for fetching, caching, and synchronizing server data. However, they differ significantly in scope and philosophy.
14
+
15
+ | Feature | TanStack Query | SWR |
16
+ |---|---|---|
17
+ | Bundle size (minified + gzip) | ~12 KB | ~4 KB |
18
+ | Framework support | React, Vue, Solid, Svelte, Angular | React only |
19
+ | Devtools | Built-in, feature-rich | Community extension |
20
+ | Mutations | First-class `useMutation` | Manual implementation |
21
+ | Infinite queries | Built-in `useInfiniteQuery` | Built-in `useSWRInfinite` |
22
+ | Offline support | Built-in | Manual |
23
+ | Query cancellation | Built-in with AbortSignal | Manual |
24
+ | Garbage collection | Configurable `gcTime` | No automatic GC |
25
+ | Optimistic updates | Built-in helpers | Manual |
26
+
27
+ ## Data Fetching
28
+
29
+ Both libraries make basic data fetching simple:
30
+
31
+ ```tsx
32
+ // TanStack Query
33
+ import { useQuery } from '@tanstack/react-query'
34
+
35
+ function Todos() {
36
+ const { data, isLoading } = useQuery({
37
+ queryKey: ['todos'],
38
+ queryFn: () => fetch('/api/todos').then((r) => r.json()),
39
+ })
40
+ }
41
+
42
+ // SWR
43
+ import useSWR from 'swr'
44
+
45
+ function Todos() {
46
+ const { data, isLoading } = useSWR('/api/todos', (url) =>
47
+ fetch(url).then((r) => r.json())
48
+ )
49
+ }
50
+ ```
51
+
52
+ SWR has a slightly more concise API for simple cases. TanStack Query requires explicit query keys and uses an object syntax exclusively.
53
+
54
+ ## Mutations
55
+
56
+ This is where the libraries diverge significantly. TanStack Query provides a dedicated `useMutation` hook:
57
+
58
+ ```tsx
59
+ // TanStack Query — built-in mutation support
60
+ const mutation = useMutation({
61
+ mutationFn: (newTodo) => fetch('/api/todos', {
62
+ method: 'POST',
63
+ body: JSON.stringify(newTodo),
64
+ }),
65
+ onSuccess: () => {
66
+ queryClient.invalidateQueries({ queryKey: ['todos'] })
67
+ },
68
+ })
69
+
70
+ // Provides isPending, isError, isSuccess, mutate, mutateAsync
71
+ mutation.mutate({ title: 'New Todo' })
72
+ ```
73
+
74
+ SWR does not have a built-in mutation hook. You typically use `useSWRMutation` from the `swr/mutation` module or handle mutations manually.
75
+
76
+ ## When to Choose TanStack Query
77
+
78
+ Choose TanStack Query when:
79
+
80
+ - You need first-class mutation support with optimistic updates
81
+ - You want built-in devtools for debugging
82
+ - Your app has complex caching requirements
83
+ - You need offline support
84
+ - You might switch frameworks in the future (Vue, Solid, etc.)
85
+
86
+ ## When to Choose SWR
87
+
88
+ Choose SWR when:
89
+
90
+ - Bundle size is critical
91
+ - You have simple data fetching needs without complex mutations
92
+ - You prefer a minimal API surface
93
+ - You are already in the Vercel/Next.js ecosystem
94
+
95
+ ## Conclusion
96
+
97
+ Both are excellent libraries. TanStack Query is more feature-rich and better suited for complex applications with lots of mutations and caching needs. SWR is lighter and simpler, ideal for applications with straightforward data fetching requirements.
98
+
99
+ > [!NOTE]
100
+ > This comparison is based on TanStack Query v5 and SWR v2. Both libraries are actively maintained and improve with each release.