-
Notifications
You must be signed in to change notification settings - Fork 287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[docs] add localization doc #462
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
# Writing Localizeable Code | ||
|
||
As part of Microsoft's commitment to global-ready products, our developer tools are localized into 14 different languages. | ||
For this effort, vcpkg has hooks that allow our localization team to translate all messages shown to the user. | ||
As a developer on vcpkg, the only thing you have to consider is the messages in the C++ source files, | ||
and `locales/messages.json` -- everything else will be generated and modified by the localization team. | ||
|
||
## Declaring a Message | ||
|
||
The process of writing a user-visible message starts with declaring it. | ||
Most user-facing messages can be declared and registered at the same time in a source file with: | ||
|
||
```cxx | ||
DECLARE_AND_REGISTER_MESSAGE(<message-name>, <parameters>, <comment>, <english-message>); | ||
``` | ||
|
||
for example, in [`sourceparagraph.cpp`]. | ||
|
||
If you need to declare a message in a header file | ||
(for example, if a templated function uses it), | ||
then you need to first declare it in the header: | ||
|
||
```cxx | ||
DECLARE_MESSAGE(<message-name>, <parameters>, <comment>, <english-message>); | ||
``` | ||
|
||
and then register it in the corresponding source file: | ||
|
||
```cxx | ||
REGISTER_MESSAGE(<message-name>); | ||
``` | ||
|
||
An example of this lies in [`graphs.h`] and [`graphs.cpp`]. | ||
|
||
[`sourceparagraph.cpp`]: https://github.com/microsoft/vcpkg-tool/blob/13a09ef0359e259627d46560a22a6e182730da7b/src/vcpkg/sourceparagraph.cpp#L24-L28 | ||
[`graphs.h`]: https://github.com/microsoft/vcpkg-tool/blob/ca8099607bfa71adac301b56c601fd71d8ccab9b/include/vcpkg/base/graphs.h#L13 | ||
[`graphs.cpp`]: https://github.com/microsoft/vcpkg-tool/blob/ca8099607bfa71adac301b56c601fd71d8ccab9b/src/vcpkg/base/graphs.cpp#L5 | ||
|
||
### Message Names | ||
|
||
Message names should be descriptive and unique, and must be `CamelCase`. | ||
When referring to a message in `msg::format`, you must add `msg` to the front of it; for example, | ||
`DECLARE_MESSAGE(MyMessage, ...)` can be referred to as `msgMyMessage`. | ||
|
||
### Parameters | ||
|
||
If the message contains placeholders, each one must have a corresponding parameter. | ||
For example, `"Installing {package_name}:{triplet}"` should have the parameter list `(msg::package_name, msg::triplet)`. | ||
This allows us to make sure that we don't have format errors, where one forgets a placeholder, | ||
or adds an extra one. | ||
Each parameter in the list should be used in the message. | ||
|
||
### Comment | ||
|
||
The comment is used to give context to the translator as to what a placeholder will be replaced with. | ||
For example, in `BuildResultSummaryHeader` (`"SUMMARY FOR {triplet}"`), | ||
it will note that an example of `{triplet}` is `'x64-windows'`. | ||
Most message placeholders (see `messages.h` for the full list - search for `DECLARE_MSG_ARG`) have comments associated with them already. | ||
Only general placeholders like `{value}`, `{expected}`, and `{actual}` don't have comments associated with them. | ||
If you use any of these placeholders, write `example of {<name>} is '<expected-value>'` for each of those placeholders, | ||
separated by `\n`. You can also add context if you feel it's necessary as the first line. | ||
|
||
### Message | ||
|
||
Messages in vcpkg are written in American English. They should not contain: | ||
|
||
* formatting: | ||
- indentation should be added with the `append_indent()` function; | ||
if you need to add more than one indentation, you can use `append_indent(N)` | ||
- newlines should be added with the `appendnl()` function | ||
- Any other interesting characters (like `- ` for lists, for example) should use `append_raw(...)` | ||
* or for the prefixes: | ||
- `"warning: "`, instead use `msg::format(msg::msgWarningMessage).append(msgMyWarning)` | ||
- `"error: "`, instead use `msg::msgErrorMessage` | ||
- `"internal error: "`, instead use `msg::msgInternalErrorMessage`. | ||
|
||
They should also not be simple, locale-invariant messages -- something like, for example, | ||
`{file}:{line}:{column}: ` should be done with `LocalizedString::from_raw(fmt::format("{}:{}:{}", file, line, column))`. | ||
|
||
Other than that, all messages that are printed to the user must be localizeable. | ||
However, that's as far as you need to go -- once you've done the writing of the message, and the `x-generate-default-message-map` stuff, | ||
you can rest easy not modifying anything else. | ||
|
||
### Putting it All Together | ||
|
||
Let's create a vcpkg hello world command to show off how one can use the messages API. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still not a fan of including a real example with a lot of code that's likely to rot rather than just linking to a real use but not over my dead body. |
||
|
||
```cxx | ||
// commands.hello-world.cpp | ||
#include <vcpkg/base/messages.h> | ||
|
||
#include <vcpkg/commands.hello-world.h> | ||
#include <vcpkg/vcpkgcmdarguments.h> | ||
#include <vcpkg/vcpkgpaths.h> | ||
|
||
namespace | ||
{ | ||
// boilerplate | ||
const CommandStructure HELLO_WORLD_COMMAND_STRUCTURE = { | ||
create_example_string("hello-world <name>"), | ||
0, | ||
1, | ||
{{}, {}, {}}, | ||
nullptr, | ||
}; | ||
|
||
// note that we add additional context in the comment here | ||
DECLARE_AND_REGISTER_MESSAGE(World, (), "We will say hello to 'world' if no name is given", "world"); | ||
// here, `{value}` is a placeholder that doesn't have example text, so we need to give it ourselves | ||
DECLARE_AND_REGISTER_MESSAGE(Hello, (msg::value), "example for {value} is 'world'", "Hello, {value}!"); | ||
// here, `{triplet}` _already has_ example text, so it's fine to not give a comment | ||
DECLARE_AND_REGISTER_MESSAGE(MyTripletIs, (msg::triplet), "", "My triplet is {triplet}."); | ||
} | ||
|
||
namespace vcpkg::Commands | ||
{ | ||
void HelloWorldCommand::perform_and_exit(const VcpkgCmdArguments& args, | ||
const VcpkgPaths& paths | ||
Triplet default_triplet, | ||
Triplet) const | ||
{ | ||
(void)args.parse_arguments(HELLO_WORLD_COMMAND_STRUCTURE); | ||
|
||
LocalizedString name; | ||
if (args.command_arguments.size() == 0) | ||
{ | ||
name = msg::format(msgWorld); | ||
} | ||
else | ||
{ | ||
name = LocalizedString::from_raw(args.command_arguments[0]); | ||
} | ||
|
||
msg::println(msgHello, msg::value = name); | ||
msg::println(msgMyTripletIs, msg::triplet = default_triplet); | ||
} | ||
} | ||
``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This part is a bit hard to follow. Maybe we should start with an example of an existing message that uses all parameters and break down each part of the declaration.