i18nSlice.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
  2. import { fetchI18nMessages, I18nMessages } from '../API/i18n/i18nActions';
  3. import { getLanguageList, changeLanguage, LanguageItem } from '../API/language';
  4. import { fetchSoftwareInfo } from '../API/softwareInfo';
  5. export interface I18nState {
  6. messages: I18nMessages;
  7. currentLocale: string;
  8. supportedLocales: string[];
  9. loading: boolean;
  10. error: string | null;
  11. // 语言管理相关状态
  12. availableLanguages: LanguageItem[];
  13. selectedLanguage: string;
  14. currentSystemLocale: string; // 当前系统语言,如 "zh"
  15. languagesLoading: boolean;
  16. savingLanguage: boolean;
  17. languageError: string | null;
  18. }
  19. const initialState: I18nState = {
  20. messages: {},
  21. currentLocale: 'en_US',
  22. supportedLocales: ['en_US', 'zh_CN'],
  23. loading: false,
  24. error: null,
  25. // 语言管理初始状态
  26. availableLanguages: [],
  27. selectedLanguage: '',
  28. currentSystemLocale: '',
  29. languagesLoading: false,
  30. savingLanguage: false,
  31. languageError: null,
  32. };
  33. // 异步thunk:加载多语言资源
  34. export const loadI18nMessages = createAsyncThunk(
  35. 'i18n/loadMessages',
  36. async (locale: string) => {
  37. const messages = await fetchI18nMessages(locale);
  38. return { locale, messages };
  39. }
  40. );
  41. // 异步thunk:加载可用语言列表
  42. export const loadAvailableLanguages = createAsyncThunk(
  43. 'i18n/loadAvailableLanguages',
  44. async () => {
  45. // 同时获取语言列表和软件信息
  46. const [languageResponse, softwareInfo] = await Promise.all([
  47. getLanguageList(),
  48. fetchSoftwareInfo(),
  49. ]);
  50. if (languageResponse.data.code === '0x000000') {
  51. // 从 softwareInfo 获取当前系统语言
  52. const currentSystemLocale = softwareInfo.current_locale;
  53. return {
  54. languages: languageResponse.data.data,
  55. currentSystemLocale,
  56. };
  57. }
  58. throw new Error(languageResponse.data.description || '加载语言列表失败');
  59. }
  60. );
  61. // 异步thunk:更新系统语言
  62. export const updateSystemLanguage = createAsyncThunk(
  63. 'i18n/updateSystemLanguage',
  64. async (language: string) => {
  65. const response = await changeLanguage(language);
  66. if (response.data.code === '0x000000') {
  67. return language;
  68. }
  69. throw new Error(response.data.description || '修改语言失败');
  70. }
  71. );
  72. const i18nSlice = createSlice({
  73. name: 'i18n',
  74. initialState,
  75. reducers: {
  76. setCurrentLocale: (state, action: PayloadAction<string>) => {
  77. state.currentLocale = action.payload;
  78. },
  79. clearError: (state) => {
  80. state.error = null;
  81. },
  82. // 设置选中的语言
  83. setSelectedLanguage: (state, action: PayloadAction<string>) => {
  84. state.selectedLanguage = action.payload;
  85. },
  86. // 清除语言错误
  87. clearLanguageError: (state) => {
  88. state.languageError = null;
  89. },
  90. },
  91. extraReducers: (builder) => {
  92. builder
  93. // 加载多语言资源
  94. .addCase(loadI18nMessages.pending, (state) => {
  95. state.loading = true;
  96. state.error = null;
  97. })
  98. .addCase(loadI18nMessages.fulfilled, (state, action) => {
  99. state.loading = false;
  100. state.messages = action.payload.messages;
  101. state.currentLocale = action.payload.locale;
  102. })
  103. .addCase(loadI18nMessages.rejected, (state, action) => {
  104. state.loading = false;
  105. state.error = action.error.message || 'Failed to load i18n messages';
  106. })
  107. // 加载可用语言列表
  108. .addCase(loadAvailableLanguages.pending, (state) => {
  109. state.languagesLoading = true;
  110. state.languageError = null;
  111. })
  112. .addCase(loadAvailableLanguages.fulfilled, (state, action) => {
  113. state.languagesLoading = false;
  114. state.availableLanguages = action.payload.languages;
  115. state.currentSystemLocale = action.payload.currentSystemLocale;
  116. // 默认选中当前系统语言
  117. if (!state.selectedLanguage) {
  118. state.selectedLanguage = action.payload.currentSystemLocale;
  119. }
  120. })
  121. .addCase(loadAvailableLanguages.rejected, (state, action) => {
  122. state.languagesLoading = false;
  123. state.languageError = action.error.message || '加载语言列表失败';
  124. })
  125. // 更新系统语言
  126. .addCase(updateSystemLanguage.pending, (state) => {
  127. state.savingLanguage = true;
  128. state.languageError = null;
  129. })
  130. .addCase(updateSystemLanguage.fulfilled, (state, action) => {
  131. state.savingLanguage = false;
  132. state.currentLocale = action.payload;
  133. })
  134. .addCase(updateSystemLanguage.rejected, (state, action) => {
  135. state.savingLanguage = false;
  136. state.languageError = action.error.message || '修改语言失败';
  137. });
  138. },
  139. });
  140. export const {
  141. setCurrentLocale,
  142. clearError,
  143. setSelectedLanguage,
  144. clearLanguageError,
  145. } = i18nSlice.actions;
  146. export default i18nSlice.reducer;