|
1 | | -# FluentLauncher.Localization |
2 | | -#### Fluent Launcher 的 本地化计划 |
| 1 | +# Fluent Launcher Localization Project |
3 | 2 |
|
4 | | -## 制定如下规定 |
| 3 | +English | [简体中文](README_zh.md) |
5 | 4 |
|
6 | | -首先 我们将一组对应的 `ViewModel.cs` 、`View.xaml` 、`View.xaml.cs` 称为一个 **视图单位**, |
7 | | -此外一些仅有的 `ViewModel.cs` 的我们也将其单独成为一个 **视图单位**, |
8 | | -如若还有一些零碎的翻译内容,我们会将其单独汇总到一些特定分类的 `.csv` 文件上 |
| 5 | +This repository provides the translation resources and localization toolchain for [Fluent Launcher](https://github.com/Xcube-Studio/Natsurainko.FluentLauncher), which currently supports the following languages: |
9 | 6 |
|
10 | | -1. 所有的语言文件均以 `.csv` 格式储存 |
11 | | -2. `.csv` 的文件名与 `View.xaml` 的文件名一致 如 `HomePage.xaml` 对应 `HomePage.csv` |
12 | | -3. 一个 `.csv` 文件应对应一个 **视图单位** (零碎汇总除外) |
13 | | -4. 所有的 `.csv` 必须以 UTF8-BOM 格式储存 |
| 7 | +- English (en-US) |
| 8 | +- Simplified Chinese (zh-Hans) |
| 9 | +- Traditional Chinese (zh-Hant) |
| 10 | +- Russian (ru-RU) |
| 11 | +- Ukrainian (uk-UA) |
14 | 12 |
|
15 | | -## .csv 文件中的存储规范 |
| 13 | +If you wish to add more languages, please submit a PR following [these instructions](#adding-a-language). Once the PR is accepted, support for the new language will be added in the next release. |
16 | 14 |
|
17 | | -`.csv` 文件中每一行的存储格式应该如下表 |
18 | | -且 `.csv` 文件中必须包含表头 表头如下 |
| 15 | +## Translation Resources |
| 16 | + |
| 17 | +All the strings in Fluent Launcher and their translations for various languages are stored in multiple `.csv` files within the `Views/` directory. To manage the large number of strings in the app efficiently, we will use the relative path to the `Views/` directory and the filename of the `.csv` file to describe the component that owns the strings in the file. During the build process of Fluent Launcher, the localization toolchain will convert these `.csv` files into PRI resources used by the WinUI app. |
| 18 | + |
| 19 | +### `.csv` File Paths |
| 20 | + |
| 21 | +Each `.csv` file in the `Views/` directory typically corresponds to a page in Fluent Launcher. The filename and path should match the corresponding page in [Natsurainko.FluentLauncher/Views](https://github.com/Xcube-Studio/Natsurainko.FluentLauncher/tree/main/Natsurainko.FluentLauncher/Views). Strings in these files may be used in the associated `View.xaml`, `View.xaml.cs`, or `ViewModel.cs`. For some components that only have a `ViewModel.cs`, the strings used are also stored in a separate `.csv` file. |
| 22 | + |
| 23 | +Other strings used in backend code are stored in specific `.csv` files, such as `Views/Exceptions.csv` and `Views/Converters.csv`. |
| 24 | + |
| 25 | +### `.csv` Content |
| 26 | + |
| 27 | +The `.csv` files storing translation resources must use UTF8-BOM encoding. Each row represents a string and its translations for all supported languages. Every `.csv` file must include the following header: |
19 | 28 |
|
20 | 29 | | Id | Property | en-US | zh-Hans | zh-Hant | ru-RU | uk-UA | |
21 | | -| ---| --- |--- | --- | --- | --- | --- | |
| 30 | +| -- | -------- | ----- | ------- | ------- | ----- | ----- | |
| 31 | + |
| 32 | + |
| 33 | +- `Id` and `Property` describe the string's path in the PRI resource system. |
| 34 | + |
| 35 | + - If the string is only used in backend code, the `Id` field must start with an `_` prefix, and the `Property` field must be empty. |
| 36 | + |
| 37 | +- Each subsequent column represents a language supported by Fluent Launcher, identified by its language code. |
| 38 | + |
| 39 | +### Adding a Language |
| 40 | + |
| 41 | +Clone this repository: |
| 42 | + |
| 43 | +```bash |
| 44 | +git clone https://github.com/Xcube-Studio/FluentLauncher.Localization.git |
| 45 | +``` |
| 46 | + |
| 47 | +Add a column to the rightmost side of each `.csv` file. Enter the new language code in the header and provide translations for each row. **Do NOT** modify the content of the `Id` and `Property` columns. The headers of all `.csv` files must remain consistent. |
| 48 | + |
| 49 | +You may submit a PR after completing partial translations. The Fluent Launcher build system allows missing translations. Untranslated strings will fall back to the content of the `en-US` column. |
| 50 | + |
| 51 | +## WinUI 3 Localization Toolchain |
| 52 | + |
| 53 | +### `.resw` Generator |
| 54 | + |
| 55 | +`FluentLauncher.Infra.Localizer` is a C# command-line tool for converting all `.csv` files in the `Views/` directory into a set of `Resources.lang-<lang>.resw` files that can be used by WinUI apps, where `<lang>` is the language code of a supported language. You can also specify a default language using the `--default-language` option. Translations of the default language will be stored in the `Resources.resw` file, which will provide the default translations of strings in the app. |
22 | 56 |
|
23 | | -**每一行的存储中,若该行为后台代码调用,应该在 `资源Id` 部分前面加上 `_` 前缀,且该行的 `资源属性Id` 留空** |
| 57 | +Each item in a `.csv` file represetns a PRI string resource. The PRI resource ID is formatted using the following pattern: |
| 58 | +`<path_relative_to_Views_directory>_<csv_file_name>_<resourceId>/<resourcePropertyId>`. |
24 | 59 |
|
25 | | -| 资源Id | 资源属性Id | 英文原文 | 简体中文 | 繁体中文 | 俄文 | 烏克蘭 | |
26 | | -| --- | --- |--- | --- | --- | --- | --- | |
| 60 | +Example: An entry in `Views/Settings/AboutPage.csv`: |
27 | 61 |
|
28 | | -> _不要问我为什么英文是原文,因为开发时用直接写英文可以避免一些麻烦,节省很多时间_ |
| 62 | +| Id | Property | en-US | zh-Hans | zh-Hant | ru-RU | uk-UA | |
| 63 | +| -- | -------- | ----------------- | -------- | -------- | ------ | ---------- | |
| 64 | +| T1 | Text | Other information | 其它信息 | 其它信息 | Другая | информация | |
29 | 65 |
|
30 | | -## 开发者事宜 |
| 66 | +Will output to the `.resw` file as: |
31 | 67 |
|
32 | | -Q: .csv 文件如何使用到项目中 |
33 | | -A: 后续我会编写一个脚本来批处理生成到对应语言文件夹的 `Resources.resw` 文件 |
| 68 | +```xml |
| 69 | +<data name="Settings_AboutPage_T1.Text" xml:space="preserve"> |
| 70 | + <value>Other information</value> |
| 71 | +</data> |
| 72 | +``` |
| 73 | + |
| 74 | +Here, `<value>` contains the translation for the corresponding language. |
| 75 | + |
| 76 | +Usage of the command-line program: |
| 77 | + |
| 78 | +```` |
| 79 | +Description: |
| 80 | + Convert .csv files to .resw files for UWP/WinUI localization |
| 81 | +
|
| 82 | +Usage: |
| 83 | + FluentLauncher.Infra.Localizer [options] |
34 | 84 |
|
35 | | -生成例子: |
| 85 | +Options: |
| 86 | + --src <src> (REQUIRED) The source folder containing the .csv files |
| 87 | + --out <out> (REQUIRED) The output folder for .resw files |
| 88 | + --languages <languages> (REQUIRED) All languages for translation |
| 89 | + --default-language <default-language> Default language of the app [] |
| 90 | + --version Show version information |
| 91 | + -?, -h, --help Show help and usage information |
| 92 | +```` |
36 | 93 |
|
37 | | -在 Views/CoresPage.csv 中 |
38 | | -| SearchBox | PlaceholderText | Search Core | 搜索核心 | 搜索核心 | поисковое ядро | пошукове ядро | |
39 | | -| --- | --- |--- | --- | --- | --- | --- | |
| 94 | +### `.resw` Resource Accessor Source Generator |
40 | 95 |
|
41 | | -`value` 为对应语言的翻译内容 |
42 | | -`name` 的拼接规则为 相对于Views文件夹的路径转换_.csv文件名字_资源Id.资源属性Id |
| 96 | +To simplify the access of PRI string resources in a WinUI project using C#, a Roslyn source generator is provided to generate the code that reads strings in the `.resw` files. The `FluentLauncher.Infra.LocalizedStrings` project provides the `GeneratedLocalizedStringsAttribute` for marking a `partial` static class, in which the string accessors will be generated as properties. Since `.resw` files are not C# source files, they need to be included as `AdditionalFiles` in the `.csproj` file of the WinUI project to allow the source generator to read them. |
43 | 97 |
|
44 | | -相对路径转换规则 |
45 | | -`Views/CoresPage.csv` => `CoresPage` |
46 | | -`Views/Activities/ActivitiesNavigationPage.csv` => `Activities_ActivitiesNavigationPage` |
| 98 | +These tools can be used in any C# WinUI project by referencing the following projects: |
47 | 99 |
|
48 | | -在 Strings/en-Us/Resources.resw 中 |
| 100 | +```xml |
| 101 | +<ItemGroup> |
| 102 | + <ProjectReference Include="..\FluentLauncher.Localization\FluentLauncher.Infra.LocalizedStrings.SourceGenerators\FluentLauncher.Infra.LocalizedStrings.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> |
| 103 | + <ProjectReference Include="..\FluentLauncher.Localization\FluentLauncher.Infra.LocalizedStrings\FluentLauncher.Infra.LocalizedStrings.csproj" /> |
| 104 | +</ItemGroup> |
49 | 105 | ``` |
50 | | - <data name="CoresPage_SearchBox.PlaceholderText" xml:space="preserve"> |
51 | | - <value>Search Core</value> |
52 | | - </data> |
| 106 | + |
| 107 | +Example: If the project contains two `.resw` files: |
| 108 | + |
| 109 | +- `Resources.resw` with two resources: |
| 110 | + |
| 111 | + - `Button1.Content` |
| 112 | + - `Sample_Message` |
| 113 | + |
| 114 | +- `TextBlocks.resw` with one resource: |
| 115 | + |
| 116 | + - `DemoTextBlock.Text` |
| 117 | + |
| 118 | + |
| 119 | +The source generator will produce the following code: |
| 120 | + |
| 121 | +```csharp |
| 122 | +[GeneratedLocalizedStrings] |
| 123 | +partial static class LocalizedStrings |
| 124 | +{ |
| 125 | + private static ResourceManager s_resourceManager; |
| 126 | + private static ResourceMap s_resourceMap; |
| 127 | + |
| 128 | + static LocalizedStrings() |
| 129 | + { |
| 130 | + s_resourceManager = new(); |
| 131 | + s_resourceMap = s_resourceManager.MainResourceMap; |
| 132 | + } |
| 133 | + |
| 134 | + // Default resource map (Resources.resw) |
| 135 | + public static string Button1_Content => s_resourceMap.GetValue("Resources/Button1/Content").ValueAsString; |
| 136 | + public static string Sample_Message => s_resourceMap.GetValue("Resources/Sample_Message").ValueAsString; |
| 137 | + |
| 138 | + // Other resw files |
| 139 | + public static class TextBlocks |
| 140 | + { |
| 141 | + public static string DemoTextBlock_Text => s_resourceMap.GetValue("TextBlocks/DemoTextBlock/Text").ValueAsString; |
| 142 | + } |
| 143 | + |
| 144 | + public static void UpdateLanguage() |
| 145 | + { |
| 146 | + s_resourceManager = new(); |
| 147 | + s_resourceMap = s_resourceManager.MainResourceMap; |
| 148 | + } |
| 149 | +} |
53 | 150 | ``` |
54 | 151 |
|
55 | | -#### 后续若还有疑问等待补充 |
| 152 | +Note: `Resources.resw` provides the default resource group in WinUI, and the source generator will generates accessors as members of the class marked by `GeneratedLocalizedStrings`. For other `.resw` files, the source generator creates a nested class named after the resource group and generates accessors within it. |
| 153 | + |
| 154 | +If the project contains multiple `.resw` files with the same name but different qualifiers, the source generator will prioritize the file without a qualifier. If all versions have qualifiers, the alphabetically first file name will be used for code generation. |
| 155 | + |
0 commit comments