Skip to content

Commit 41911f1

Browse files
committed
docs: Add code guidelines for translations
1 parent ab3c6cc commit 41911f1

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

Docs/Code Guidelines.md

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
- Use the most appropriate logging method:
77
- When parsing files, use [file format logging methods](#file-format-logging-methods)
88
- 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"
1010
- Do not make reference to the user or Open Rails itself
1111
- Include the most relevant source file and line number at the end of the message (_file format logging methods_ do this for you)
1212

@@ -60,3 +60,89 @@ When parsing files, use the specific logger methods below to automatically inclu
6060
Trace.TraceWarning("Skipped unknown texture addressing mode {1} in shape {0}", shapeFileName, addressingMode);
6161
Trace.TraceInformation("Ignored missing animation data in shape {0}", shapeFileName);
6262
```
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

Comments
 (0)