|
6 | 6 | - Use the most appropriate logging method: |
7 | 7 | - When parsing files, use [file format logging methods](#file-format-logging-methods) |
8 | 8 | - Otherwise, use [general logging methods](#general-logging-methods) |
9 | | -- Use [simple past tense](https://en.wikipedia.org/wiki/Simple_past) with the verb at the front; e.g. "Ignored missing texture file" instead of "Missing texture file was ignored". |
| 9 | +- Use [simple past tense](https://en.wikipedia.org/wiki/Simple_past) with the verb at the front; e.g. "Ignored missing texture file" instead of "Missing texture file was ignored" |
10 | 10 | - Do not make reference to the user or Open Rails itself |
11 | 11 | - Include the most relevant source file and line number at the end of the message (_file format logging methods_ do this for you) |
12 | 12 |
|
@@ -60,3 +60,89 @@ When parsing files, use the specific logger methods below to automatically inclu |
60 | 60 | Trace.TraceWarning("Skipped unknown texture addressing mode {1} in shape {0}", shapeFileName, addressingMode); |
61 | 61 | Trace.TraceInformation("Ignored missing animation data in shape {0}", shapeFileName); |
62 | 62 | ``` |
| 63 | + |
| 64 | +## Translations |
| 65 | + |
| 66 | +- Use translations for all user-visible text |
| 67 | +- Use English (United States) for all translations |
| 68 | +- Use [entire sentences](#entire-sentences) appropriately |
| 69 | +- Use [nested values](#nested-values) appropriately |
| 70 | +- Use [context](#context) appropriately |
| 71 | +- Use [dynamic values](#dynamic-values) appropriately |
| 72 | + |
| 73 | +### Entire sentences |
| 74 | + |
| 75 | +Not all languages put words in the same order, or even have a concept of "words". For this reason, only translate entire sentences. Never concatenate multiple translations to form a longer string of text. [Nested values](#nested-values) are allowed under specific conditions. |
| 76 | + |
| 77 | +### Nested values |
| 78 | + |
| 79 | +In a formatted string, each placeholder is replaced with a nested value, which appears adjacent of the formatting string. For this reason, delimiters are needed to separate nested values from the surrounding text. Otherwise, it does not meet the [entire sentences](#entire-sentences) requirement. For example: |
| 80 | + |
| 81 | +- **Allowed:** Opening "{0}" doors... |
| 82 | +- **Allowed:** Opening doors on: {0} |
| 83 | +- **Not allowed:** Opening {0} doors... |
| 84 | +- **Not allowed:** Opening doors on {0} |
| 85 | + |
| 86 | +### Context |
| 87 | + |
| 88 | +Not all sentences or values which must be translated will make sense when seen on their own. For this reason, additional context is added in the code to provide translators with the necessary information to correctly translate them. The context is only shown to translators and does not form part of the translation itself. |
| 89 | + |
| 90 | +### Dynamic values |
| 91 | + |
| 92 | +Dynamic values are those that depend on the state of the application and can be used stand-alone or as [nested values](#nested-values). They may or may not use [context](#context). |
| 93 | + |
| 94 | +- For boolean values, use two static values |
| 95 | +- For enumerated values, use `GetStringAttribute` and `GetParticularStringAttribute` as attributes and static methods |
| 96 | +- For numeric values with units, use `Format...()` methods from static class `FormatStrings` |
| 97 | + |
| 98 | +### Examples |
| 99 | + |
| 100 | +- For a context-free static sentence: |
| 101 | + ```csharp |
| 102 | + Catalog.GetString("Opening doors on left..."); |
| 103 | + ``` |
| 104 | +- For a context-free static sentence with a nested value: |
| 105 | + ```csharp |
| 106 | + Catalog.GetStringFmt("Opening doors on: {0}", ...); |
| 107 | + // Shortcut for: string.Format(Catalog.GetString("Opening doors on: {0}"), ...); |
| 108 | + ``` |
| 109 | +- For a context-sensitive static sentence: |
| 110 | + ```csharp |
| 111 | + Catalog.GetParticularString("Doors", "Opening on left..."); |
| 112 | + ``` |
| 113 | +- For a context-sensitive static sentence with a nested value: |
| 114 | + ```csharp |
| 115 | + // No shortcut available, so use: |
| 116 | + string.Format(Catalog.GetParticularString("Doors", "Open on: {0}"), ...); |
| 117 | + ``` |
| 118 | +- For a context-free boolean dynamic value: |
| 119 | + ```csharp |
| 120 | + return doorsOpen ? Catalog.GetString("Doors open") : Catalog.GetString("Doors closed") |
| 121 | + ``` |
| 122 | +- For a context-sensitive boolean dynamic value: |
| 123 | + ```csharp |
| 124 | + return doorsOpen ? Catalog.GetParticularString("Doors", "Open") : Catalog.GetParticularString("Doors", "Closed") |
| 125 | + ``` |
| 126 | +- For a context-free enumerated dynamic value: |
| 127 | + ```csharp |
| 128 | + enum Actions |
| 129 | + { |
| 130 | + [GetString("Doors Left Open")]DoorsLeftOpen, |
| 131 | + [GetString("Doors Left Close")]DoorsLeftClose, |
| 132 | + } |
| 133 | + return GetStringAttribute.GetPrettyName(action); |
| 134 | + ``` |
| 135 | +- For a context-sensitive enumerated dynamic value: |
| 136 | + ```csharp |
| 137 | + enum Actions |
| 138 | + { |
| 139 | + [GetParticularString("Doors", "Left Open")]DoorsLeftOpen, |
| 140 | + [GetParticularString("Doors", "Left Close")]DoorsLeftClose, |
| 141 | + } |
| 142 | + return GetParticularStringAttribute.GetParticularPrettyName("Doors", action); |
| 143 | + ``` |
| 144 | +- For a numeric unit dynamic value: |
| 145 | + ```csharp |
| 146 | + // There are about 30 of these `FormatStrings.Format...()` functions available: |
| 147 | + return FormatStrings.FormatDistance(distanceM, isMetric) |
| 148 | + ``` |
0 commit comments