com.xmobitea.changx.mini-localization 1.5.0 → 1.5.1

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.
package/AGENTS.md CHANGED
@@ -1,67 +1,107 @@
1
- # XmobiTea Localization Package Notes
1
+ # XmobiTea Localization Agent Guide
2
2
 
3
- This file defines the usage contract of this package for AI coding agents and maintainers.
3
+ Scope: everything inside `Assets/XmobiTea Localization`.
4
4
 
5
- ## Scope
5
+ ## Need-Based Routing
6
6
 
7
- Applies to everything inside this package folder.
7
+ Choose by current need. Open the smallest file that answers it.
8
8
 
9
- ## Hard Rules
10
-
11
- - `LocalizationManager` is a scene-hosted singleton and must exist before static APIs are used.
12
- - `LocalizationSettings` must exist in `Resources` under the configured resource path.
13
- - runtime localization is key-based and dictionary-backed.
14
- - `ChooseLanguage(...)` is the operation that actually populates the active text dictionary.
15
- - `GetText(...)` falls back to the original key when translation is missing.
16
- - UI text updates happen through `LocalizationManager.OnUpdateText`.
17
- - online localization success clears and rebuilds the active dictionary from the downloaded XML.
18
- - generated key constants come from editor tooling, not from runtime discovery.
19
- - `FetchType` controls the editor fetch source: `None`, `FromGoogleSheets`, or `FromCsv`.
20
- - CSV fetch reads a `TextAsset` assigned in settings, parses it with `CsvParser`, and writes XML files to disk. It does not alter the runtime dictionary directly.
21
-
22
- ## Required Mental Model
23
-
24
- Treat this package as:
25
-
26
- - a scene-managed localization system,
27
- - XML-driven translation storage at runtime,
28
- - CSV-driven or Google-Sheets-driven fetch workflow in the editor (CSV is converted to XML before being used at runtime),
29
- - key-based lookup plus UI refresh events,
30
- - editor-assisted setup and code generation.
31
-
32
- Do not treat this package as:
33
-
34
- - an auto-configuring localization framework,
35
- - a strongly typed localization database,
36
- - a schema-validated content pipeline,
37
- - a one-shot synchronous load system when addressable or online sources are enabled.
38
-
39
- ## Correct Usage Pattern
9
+ | Need | Use |
10
+ | --- | --- |
11
+ | Choose localization API or generate common runtime code | `AI_USAGE.md` |
12
+ | Setup router | `AI_SETUP.md` |
13
+ | Scene object, singleton timing, bootstrap, persistent manager | `AI_SETUP_LOCALIZATION_MANAGER.md` |
14
+ | Settings asset, language items, XML, CSV/Google import, constants | `AI_SETUP_LOCALIZATION_SETTINGS.md` |
15
+ | Exact signatures, return values, serialized fields, XML shape, editor menus | `AI_API_REFERENCE.md` |
16
+ | Lifecycle, source precedence, async refreshes, fetch edge cases | `AI_BEHAVIOR.md` |
17
+ | Package summary for humans | `README.md` |
18
+ | Missing or conflicting doc detail | source code |
40
19
 
41
- When generating or reviewing code, assume the valid pattern is:
42
-
43
- 1. Ensure `LocalizationManager` exists in scene.
44
- 2. Ensure `LocalizationSettings` exists in `Resources`.
45
- 3. Configure one or more `LocalizationLanguageItem` entries.
46
- 4. Call `ChooseLanguage(...)` during bootstrap.
47
- 5. Bind UI through localization components or direct `GetText(...)` calls.
48
-
49
- ## Incorrect Assumptions
50
-
51
- These assumptions are false:
52
-
53
- - translations are active immediately just because the manager exists.
54
- - generated constants always exist without editor generation.
55
- - online localization merges into local localization without replacing it.
56
- - `GetText(...)` returns null when a key is missing.
57
-
58
- ## Operational Consequences
59
-
60
- If an agent writes code against this package:
20
+ ## Hard Rules
61
21
 
62
- - it should mention the need for scene setup and settings asset,
63
- - it should not assume constants are available unless generation is part of the workflow,
64
- - it should account for repeated `OnUpdateText` when async sources are enabled,
65
- - it should document any changed XML or load-order semantics in `README.md`,
66
- - when describing the fetch workflow, it should distinguish between `FromGoogleSheets` (runs an external executable) and `FromCsv` (reads a `TextAsset` inside the project and converts it to XML),
67
- - it should never imply that CSV is read at runtime CSV is an editor-only input format.
22
+ - `LocalizationManager` is a scene-hosted `Singleton<LocalizationManager>`.
23
+ - The package does not auto-create a missing manager.
24
+ - Static APIs require the singleton to initialize first.
25
+ - The conventional host object name is `LocalizationManager`, but runtime depends on the initialized component.
26
+ - Use `XmobiTea.MiniSingleton.DontDestroy` only when later scenes need the same host.
27
+ - Runtime settings lookup key is `XmobiTea LocalizationSettings`; `Open Settings` creates the asset at `Assets/Resources/XmobiTea LocalizationSettings.asset`.
28
+ - `LocalizationSettings.ResourcesPath` is exactly `XmobiTea LocalizationSettings`.
29
+ - `ChooseLanguage(...)` populates the active dictionary.
30
+ - `GetText(...)` falls back to the original key.
31
+ - `LocalizationComponent` targets `UnityEngine.UI.Text`.
32
+ - `TMP_LocalizationComponent` targets `TMP_Text` and exists only with TextMesh Pro support.
33
+ - Fixed labels, titles, descriptions, tabs, and button captions should use localization components.
34
+ - `LocalizationManager.OnUpdateText` is a public static `Action`; subscribe with `+=`/`-=` and never overwrite it.
35
+ - Local XML loads synchronously first.
36
+ - Addressables XML can add/overwrite keys after async load completes.
37
+ - Successful online XML clears and replaces the active dictionary.
38
+ - If one language configures both Addressables XML and online XML, both async loads run and the callback that finishes later mutates the dictionary last.
39
+ - `OnUpdateText` can fire more than once for one `ChooseLanguage(...)` call.
40
+ - Runtime never reads CSV or Google Sheets.
41
+ - `fetchType` is editor-only: `None`, `FromGoogleSheets`, `FromCsv`.
42
+ - `worksheetKey` is required only when either fetch type is `FromGoogleSheets`.
43
+ - CSV rows must include `Key` plus one cell per configured language.
44
+ - Generated constants come from editor tooling, not runtime discovery.
45
+ - Generated `LocalizationConstantId` members are `public static readonly string`.
46
+ - The generator reads keys from the first configured language item's local XML.
47
+
48
+ ## Do Not Assume
49
+
50
+ - `LocalizationManager` or `LocalizationSettings` will be created at runtime.
51
+ - Translations are active before `ChooseLanguage(...)`.
52
+ - A missing key returns `null`.
53
+ - One language switch means exactly one `OnUpdateText` call.
54
+ - Online XML merges with local XML.
55
+ - CSV or Google Sheets are runtime data sources.
56
+ - Generated constants are type-safe or auto-updated.
57
+ - Keys missing from the first local XML will generate constants.
58
+ - Nonexistent APIs exist: `SetLanguage`, `CurrentLanguage`, `GetLocalizedText`, `ReloadLanguage`, `FormatText`, `HasKey`.
59
+
60
+ ## Code Generation Guidance
61
+
62
+ - Use `using XmobiTea.MiniLocalization;`.
63
+ - Add `using XmobiTea.MiniLocalization.Core;` only when declaring `LocalizationLanguageItem`.
64
+ - Prefer generated `LocalizationConstantId` values when the generated file exists and is current.
65
+ - Use raw key strings in fresh setups until constants are generated.
66
+ - Put language selection in `Start()` or later unless execution order guarantees manager initialization.
67
+ - Generate scene setup instructions instead of constructing a manager from code.
68
+ - Use `LocalizationComponent` / `TMP_LocalizationComponent` for fixed UI text.
69
+ - Generate custom text refresh code only for dynamic/composed text, non-UI state, or custom rendering.
70
+ - Custom listeners must unsubscribe and must tolerate repeated refreshes.
71
+ - Treat fallback-to-key display as normal runtime behavior.
72
+ - Before using constants, verify the first configured language XML contains the complete key set.
73
+ - Use `Samples~/Example` as the known-good CSV/XML shape.
74
+
75
+ ## Setup Contract
76
+
77
+ When generated code depends on localization, require:
78
+
79
+ 1. A loaded scene contains one active `LocalizationManager`.
80
+ 2. Static APIs run after `LocalizationManager.Awake()`.
81
+ 3. A `LocalizationSettings` asset loadable as `Resources.Load<LocalizationSettings>("XmobiTea LocalizationSettings")` exists.
82
+ 4. `localizationLanguageItems` contains the requested language.
83
+ 5. Runtime language items have local XML unless deliberately online/addressable-only.
84
+ 6. Bootstrap calls `ChooseLanguage(...)`.
85
+ 7. Fixed UI text uses localization components.
86
+ 8. Constants are regenerated after key changes.
87
+ 9. Fetch workflows verify assigned CSV assets, local XML targets, Google `worksheetKey`, and complete language columns.
88
+
89
+ ## Maintenance Checklist
90
+
91
+ If changing resource paths, manager lifecycle, XML parsing, source precedence, generated constants, editor fetch behavior, component binding, or event semantics, update these together:
92
+
93
+ - `Runtime/LocalizationManager.cs`
94
+ - `Runtime/LocalizationSettings.cs`
95
+ - `Runtime/LocalizationLanguageItem.cs`
96
+ - `Runtime/LocalizationComponent.cs`
97
+ - `Runtime/TMP_LocalizationComponent.cs`
98
+ - `Editor/LocalizationManagerEditor.cs`
99
+ - `Editor/LocalizationSettingsEditor.cs`
100
+ - `Editor/LocalizationKeyDrawer.cs`
101
+ - `AI_USAGE.md`
102
+ - `AI_SETUP.md`
103
+ - `AI_SETUP_LOCALIZATION_MANAGER.md`
104
+ - `AI_SETUP_LOCALIZATION_SETTINGS.md`
105
+ - `AI_API_REFERENCE.md`
106
+ - `AI_BEHAVIOR.md`
107
+ - `README.md`
@@ -0,0 +1,281 @@
1
+ # AI API Reference For XmobiTea Localization
2
+
3
+ Read this only when exact signatures, return values, serialized fields, XML shape, or editor menu names matter. Use `AI_SETUP_LOCALIZATION_MANAGER.md` for manager setup and `AI_SETUP_LOCALIZATION_SETTINGS.md` for settings/import preflight.
4
+
5
+ Required imports for runtime usage:
6
+
7
+ ```csharp
8
+ using UnityEngine;
9
+ using XmobiTea.MiniLocalization;
10
+ ```
11
+
12
+ Additional import only when code declares `LocalizationLanguageItem` directly:
13
+
14
+ ```csharp
15
+ using XmobiTea.MiniLocalization.Core;
16
+ ```
17
+
18
+ ## LocalizationManager API
19
+
20
+ | Signature | Returns | Use for | Missing manager |
21
+ | --- | --- | --- | --- |
22
+ | `public static bool ChooseLanguage(SystemLanguage systemLanguage)` | `true` on accepted language, otherwise `false` | activate or switch language | logs error and returns `false` |
23
+ | `public static string GetText(string key)` | translated text or original `key` | direct string lookup | returns `key` |
24
+ | `public static LocalizationLanguageItem GetCurrentLanguage()` | active item or `null` | inspect selected language | logs error and returns `null` |
25
+ | `public static LocalizationLanguageItem[] GetAllLanguageItem()` | configured items or `null` | show language choices | logs error and returns `null` |
26
+ | `public static string GetTextWithoutBOM(TextAsset textAsset)` | text content | helper for XML `TextAsset` parsing | no manager needed; `textAsset` must be non-null |
27
+ | `public static Action OnUpdateText` | event field | refresh custom state after dictionary updates | no automatic guard |
28
+
29
+ `ChooseLanguage(...)` returns `false` when the requested `SystemLanguage` is not configured.
30
+
31
+ `GetAllLanguageItem()` reloads `LocalizationSettings` from `Resources`; it does not return a cached copy from the active language dictionary.
32
+
33
+ `OnUpdateText` is a public static `Action` field, not a C# `event`. Subscribe with `+=` and unsubscribe with `-=`. Do not assign it with `=` or set it to `null`.
34
+
35
+ ## Component API
36
+
37
+ | Type | Target | Use for | Key field |
38
+ | --- | --- | --- | --- |
39
+ | `LocalizationComponentBase : MonoBehaviour` | abstract | shared event subscription and key storage | `[LocalizationKey] protected string _key` |
40
+ | `LocalizationComponent : LocalizationComponentBase` | `UnityEngine.UI.Text` | UGUI text binding | `key` property |
41
+ | `TMP_LocalizationComponent : LocalizationComponentBase` | `TMP_Text` | TextMesh Pro binding | `key` property |
42
+
43
+ `TMP_LocalizationComponent` is compiled only when `UNITY_USING_TMPRO` is defined by the package asmdef version define for `com.unity.textmeshpro`.
44
+
45
+ `LocalizationComponentBase` exposes:
46
+
47
+ ```csharp
48
+ public string key { get; set; }
49
+ public virtual void OnUpdateText();
50
+ ```
51
+
52
+ Lifecycle behavior:
53
+
54
+ - `OnEnable()` removes then adds `OnUpdateText` to `LocalizationManager.OnUpdateText`.
55
+ - `OnEnable()` immediately calls `OnUpdateText()`.
56
+ - `OnDisable()` unsubscribes.
57
+
58
+ `LocalizationComponent` auto-fills its target only in `OnValidate()` when the serialized target is empty and the component sits on the same object as `Text`. The same pattern applies to `TMP_LocalizationComponent`.
59
+
60
+ ## LocalizationSettings API
61
+
62
+ ```csharp
63
+ public enum FetchType
64
+ {
65
+ None = 0,
66
+ FromGoogleSheets = 1,
67
+ FromCsv = 2,
68
+ }
69
+
70
+ public class LocalizationSettings : ScriptableObject
71
+ {
72
+ public const string ResourcesPath = "XmobiTea LocalizationSettings";
73
+ public string worksheetKey { get; }
74
+ public LocalizationLanguageItem[] localizationLanguageItems { get; }
75
+ public FetchType fetchTypeLocalLocalization { get; }
76
+ public string sheetnameFetchLocalLocalization { get; }
77
+ public TextAsset csvFetchLocalLocalization { get; }
78
+ public FetchType fetchTypeOnlineLocalization { get; }
79
+ public string sheetnameFetchOnlineLocalization { get; }
80
+ public TextAsset csvFetchOnlineLocalization { get; }
81
+ }
82
+ ```
83
+
84
+ Serialized fields in the asset:
85
+
86
+ | Inspector field | Runtime property | Used by |
87
+ | --- | --- | --- |
88
+ | `_worksheetKey` | `worksheetKey` | editor Google Sheets fetch; required when either fetch type is `FromGoogleSheets` |
89
+ | `_localizationLanguageItems` | `localizationLanguageItems` | runtime language registry |
90
+ | `_fetchTypeLocalLocalization` | `fetchTypeLocalLocalization` | editor local import |
91
+ | `_sheetNameFetchLocalLocalization` | `sheetnameFetchLocalLocalization` | editor Google Sheets local import |
92
+ | `_csvFetchLocalLocalization` | `csvFetchLocalLocalization` | editor CSV local import |
93
+ | `_fetchTypeOnlineLocalization` | `fetchTypeOnlineLocalization` | editor online-file import |
94
+ | `_sheetNameFetchOnlineLocalization` | `sheetnameFetchOnlineLocalization` | editor Google Sheets online import |
95
+ | `_csvFetchOnlineLocalization` | `csvFetchOnlineLocalization` | editor CSV online import |
96
+
97
+ Default asset path created by `Open Settings`:
98
+
99
+ ```text
100
+ Assets/Resources/XmobiTea LocalizationSettings.asset
101
+ ```
102
+
103
+ Runtime load:
104
+
105
+ ```csharp
106
+ Resources.Load<LocalizationSettings>(LocalizationSettings.ResourcesPath)
107
+ ```
108
+
109
+ ## LocalizationSettings Inspector Setup
110
+
111
+ Use this checklist when generating setup instructions:
112
+
113
+ | Inspector field | Required when | Value rule |
114
+ | --- | --- | --- |
115
+ | `Localization Language Length` | always | inspector-only size control that resizes `_localizationLanguageItems` |
116
+ | `systemLanguage` | always per language | Unity `SystemLanguage` value |
117
+ | `flagSpr` | optional | display icon only |
118
+ | `xml` | normal runtime local XML | assign an existing XML `TextAsset` asset |
119
+ | `xmlRef` | optional Addressables runtime XML | shown only when Addressables is installed |
120
+ | `onlineLocalizationUrl` | optional online runtime XML | URL must return parser-compatible XML |
121
+ | `fetchTypeLocalLocalization` | editor import | `None`, `FromGoogleSheets`, or `FromCsv` |
122
+ | `sheetNameFetchLocalLocalization` | local `FromGoogleSheets` | Google Sheet tab name; avoid spaces |
123
+ | `csvFetchLocalLocalization` | local `FromCsv` | CSV `TextAsset` imported into Unity |
124
+ | `fetchTypeOnlineLocalization` | editor import | `None`, `FromGoogleSheets`, or `FromCsv` |
125
+ | `sheetNameFetchOnlineLocalization` | online `FromGoogleSheets` | Google Sheet tab name; avoid spaces |
126
+ | `csvFetchOnlineLocalization` | online `FromCsv` | CSV `TextAsset` imported into Unity |
127
+ | `worksheetKey` | any `FromGoogleSheets` fetch | non-empty Google spreadsheet id/key |
128
+
129
+ For local imports, the editor writes fetched content into each configured language item's assigned `XML` asset path. Create placeholder XML assets and assign them before fetching.
130
+
131
+ Inspector visibility: `Worksheet Key` is shown only when at least one fetch type is `FromGoogleSheets`. CSV-only import does not require `worksheetKey`.
132
+
133
+ ## Import Data Shape
134
+
135
+ Google Sheet and CSV import use the same column model:
136
+
137
+ ```text
138
+ Key,English,Vietnamese
139
+ Home_Title,Home,Trang chu
140
+ Home_Subtitle,Welcome,Chao mung
141
+ ```
142
+
143
+ Rules:
144
+
145
+ - first row is header;
146
+ - first column is key;
147
+ - subsequent columns map to `localizationLanguageItems` order;
148
+ - column names should match the intended languages for human clarity;
149
+ - every data row must contain `Key` plus one cell per configured language;
150
+ - empty values generate empty XML text nodes;
151
+ - CSV delimiter is comma.
152
+
153
+ `Fetch Localization` is editor-only. It converts external data into XML and regenerates constants; runtime reads XML, Addressables XML, or online XML URL only.
154
+
155
+ ## LocalizationLanguageItem API
156
+
157
+ Namespace:
158
+
159
+ ```csharp
160
+ XmobiTea.MiniLocalization.Core
161
+ ```
162
+
163
+ Shape:
164
+
165
+ ```csharp
166
+ public class LocalizationLanguageItem
167
+ {
168
+ public SystemLanguage systemLanguage { get; }
169
+ public Sprite flagSpr { get; }
170
+ public TextAsset xml { get; set; }
171
+ public string onlineLocalizationUrl { get; set; }
172
+ }
173
+ ```
174
+
175
+ When Addressables is installed:
176
+
177
+ ```csharp
178
+ public AssetReferenceT<TextAsset> xmlRef { get; set; }
179
+ ```
180
+
181
+ One item can provide local XML, optional Addressables XML, and optional online XML URL for the same language.
182
+
183
+ If both `xmlRef` and `onlineLocalizationUrl` are configured, both async loads run independently. The callback that finishes later mutates the active dictionary last.
184
+
185
+ ## Editor Menus
186
+
187
+ | Menu | Effect |
188
+ | --- | --- |
189
+ | `XmobiTea Tools/Localization/Open Settings` | creates or selects `Assets/Resources/XmobiTea LocalizationSettings.asset` |
190
+ | `XmobiTea Tools/Localization/Show LocalizationComponentWindows` | opens bulk UI text binding window |
191
+ | `XmobiTea Tools/Localization/Generate LocalizationConstantId.cs` | generates constants from the first language item's local XML |
192
+ | `XmobiTea Tools/Localization/Fetch Localization` | imports local/online XML files from configured editor sources, then regenerates constants |
193
+
194
+ Inspector buttons on `LocalizationManager` and `LocalizationSettings` mirror the window, generate, and fetch actions.
195
+
196
+ ## Generated Constants
197
+
198
+ Runtime package file:
199
+
200
+ ```csharp
201
+ namespace XmobiTea.MiniLocalization
202
+ {
203
+ public partial class LocalizationConstantId { }
204
+ }
205
+ ```
206
+
207
+ Generated file path:
208
+
209
+ ```text
210
+ Assets/XmobiTea-constant/Scripts/LocalizationConstantId.cs
211
+ ```
212
+
213
+ Generated shape:
214
+
215
+ ```csharp
216
+ namespace XmobiTea.MiniLocalization
217
+ {
218
+ public partial class LocalizationConstantId
219
+ {
220
+ public static readonly string Home_Title = "Home_Title";
221
+ }
222
+ }
223
+ ```
224
+
225
+ Generator behavior:
226
+
227
+ - reads only the first configured language item's local XML;
228
+ - converts invalid C# field-name characters to `_`;
229
+ - removes diacritics;
230
+ - prefixes digit-starting names and C# keywords with `_`;
231
+ - logs duplicate generated field names and skips later duplicates.
232
+
233
+ Generated members are `public static readonly string`, not `const`.
234
+
235
+ ## XML Shape
236
+
237
+ Runtime parser accepts any root and section tag names as long as the document has the expected node order, keys are two levels below the root, and each key node has a `name` attribute.
238
+
239
+ Minimal valid XML:
240
+
241
+ ```xml
242
+ <?xml version='1.0' encoding='utf-8'?>
243
+ <English>
244
+ <section name='Local'>
245
+ <key name='Home_Title'>Home</key>
246
+ </section>
247
+ </English>
248
+ ```
249
+
250
+ Parser rules:
251
+
252
+ - expects the root element at `xmlDoc.ChildNodes.Item(1)`, so generated or hand-authored XML should include the XML declaration;
253
+ - reads `xmlDoc.ChildNodes.Item(1)` as root;
254
+ - loops each section node under root;
255
+ - loops each key node under each section;
256
+ - reads key from `node.Attributes.GetNamedItem("name").Value`;
257
+ - reads text from `node.InnerText`;
258
+ - logs duplicate keys and overwrites with the later value.
259
+
260
+ Text replacements after XML read:
261
+
262
+ | Stored text | Runtime text |
263
+ | --- | --- |
264
+ | `\\n` | newline |
265
+ | `&lt;` | `<` |
266
+ | `&gt;` | `>` |
267
+ | `&#38;` | `&` |
268
+ | `&#39;` | `'` |
269
+ | `&#34;` | `"` |
270
+
271
+ ## Error And Fallback Guards
272
+
273
+ - Missing manager: `ChooseLanguage` returns `false`; `GetText` returns the input key; language getters return `null`.
274
+ - Missing settings during manager init: logs `[Localization] Missing XmobiTea LocalizationSettings` and no language registry is built.
275
+ - Missing language in settings: `ChooseLanguage(...)` logs an error and returns `false`.
276
+ - Missing key: `GetText(key)` returns `key`.
277
+ - Empty key: `GetText(key)` returns `key`.
278
+ - Duplicate XML key: logs an error and overwrites with the later value.
279
+ - Missing local XML: local sync load is skipped; optional Addressables or online sources may still update later if configured.
280
+ - Missing first language XML during constant generation: generator can throw while reading or parsing.
281
+ - Missing CSV asset or missing CSV language columns during fetch: editor code can throw before generating XML.
@@ -0,0 +1,7 @@
1
+ fileFormatVersion: 2
2
+ guid: 19e4dcbe1d834c71a35f28c173c7f46d
3
+ TextScriptImporter:
4
+ externalObjects: {}
5
+ userData:
6
+ assetBundleName:
7
+ assetBundleVariant: