This commit is contained in:
Geoff Lankow 2023-01-17 16:03:08 +13:00
Родитель 506d4d8be2 adfe5f0ca9
Коммит 4758969d5e
18 изменённых файлов: 241 добавлений и 89 удалений

Просмотреть файл

@ -141,3 +141,5 @@ fdf6e7ccc0aaef99cba75d02c58b8fdca45b150a NIGHTLY_103_END
5e8f22244df03dfd4eb383a8688df44cd2d24752 NIGHTLY_108_END
21ce17b950114437f716947e460a1dff0cd041fa BETA_109_BASE
c085c6203989d620f77410fc207ab04f625f09cd NIGHTLY_109_END
ae431256747870c95941817df69666a383f0545a BETA_110_BASE
31883a704fda918f2ef5fc4c544126eeb81f2f5d NIGHTLY_110_END

Просмотреть файл

@ -12,6 +12,8 @@ Thunderbird Source Tree Documentation
mots/index
l10n/index
Indices and tables

Просмотреть файл

@ -0,0 +1,143 @@
# Migrating Strings to Fluent Files
Like [Firefox](https://firefox-source-docs.mozilla.org/l10n/migrations/index.html),
Thunderbird developers are working on migrating strings from legacy formats to
Fluent. The process is very similar to how migrations are done for Firefox. The
differences are detailed below.
## Migration Recipes
When part of Thunderbirds UI is migrated to Fluent, a migration recipe should
be included in the same patch that adds new strings to .ftl files. Recipies are
stored in [comm-central](https://hg.mozilla.org/comm-central/file/tip/python/l10n/tb_fluent_migrations).
After a patch with migrations landed, it will be run for all locales as part of
the [Thunderbird Cross-Channel string quarantining process](cross_channel.md).
Be sure to read [Migrating Legacy Formats](https://firefox-source-docs.mozilla.org/l10n/migrations/legacy.html)
along with the below example.
The migration recipes filename should start with a reference to the associated
bug number, and include a brief description of the bug, e.g. `bug_1805746_calendar_view.py`
for the below example.
### Example: Migrate Multiple DTD strings to Fluent
Often, strings are migrated as part of ongoing UI work to convert XUL code
to HTML. Multiple DTD strings may convert to a single Fluent string with
attributes. It really depends on the document structure and what the UI changes
are doing.
**Legacy strings are in `comm/calendar/locales/en-US/chrome/calendar/calendar.dtd`**
```dtd
<!ENTITY calendar.day.button.tooltip "Switch to day view" >
<!ENTITY calendar.day.button.label "Day" >
```
**The (simplified) XUL code**
```xml
<radio id="calendar-day-view-button"
label="&calendar.day.button.label;"
tooltiptext="&calendar.day.button.tooltip;" />
```
**The new HTML**
```html
<button id="calTabDay" data-l10n-id="calendar-view-toggle-day"></button>
```
**The new FTL string**
```fluent
calendar-view-toggle-day = Day
.title = Switch to day view
```
**Renders as:**
```html
<button id="calTabDay" title="Switch to day view">Day</button>
```
This case migrates two DTD strings, `calendar.day.button.label` and `calendar.day.button.tooltip`
to create a single FTL string, `calendar-view-toggle-day`, with one (`title`)
attribute.
**The migration recipe:**
```python
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
from fluent.migrate.helpers import transforms_from
from fluent.migrate import COPY
def migrate(ctx):
"""Bug 1805746 - Update Calendar View selection part {index}."""
target = "calendar/calendar/calendar-widgets.ftl"
reference = "calendar/calendar/calendar-widgets.ftl"
ctx.add_transforms(
target,
reference,
transforms_from(
"""
calendar-view-toggle-day = { COPY(from_path, "calendar.day.button.label") }
.title = { COPY(from_path, "calendar.day.button.tooltip") }
""",
from_path="calendar/chrome/calendar/calendar.dtd",
),
)
```
Migrations are Python modules, and implement
a single `migrate(MigrationContext)` function. The `migrate()` function makes
calls into `MigrationContext.add_transforms()`.
The `add_transforms()` function takes three arguments:
- `target_path`: Path to the target l10n file
- `reference_path`: Path to the reference (en-US) file
- A list of Transforms
```{note}
For Thunderbird migrations, the target and reference path are the same.
```
Transforms are rather dense AST nodes. See
[Transforms](https://firefox-source-docs.mozilla.org/l10n/migrations/overview.html#transforms)
for the exact details.
There are some helper functions that simplify creating the ASTs. The above example uses the
`transforms_from()` helper function. It is equivalent to:
```python
ctx.add_transforms(
"calendar/calendar/calendar-widgets.ftl",
"calendar/calendar/calendar-widgets.ftl",
[
FTL.Message(
id=FTL.Identifier("calendar-view-toggle-day"),
value=COPY("calendar/chrome/calendar/calendar.dtd", "calendar.day.button.label"),
attributes=[
FTL.Attribute(
id=FTL.Identifier("title"),
value=COPY(
"calendar/chrome/calendar/calendar.dtd",
"calendar.day.button.tooltip"
)
)
]
)
]
)
```
`transforms_from()` allows copying reference FTL strings, and replacing the value
of each message with a `COPY` Transform that copies values from the DTD file at
`from_path`.
There are other Transforms like `COPY`. See
[Migrating Legacy Formats](https://firefox-source-docs.mozilla.org/l10n/migrations/legacy.html)
for usage information.

16
docs/l10n/index.md Normal file
Просмотреть файл

@ -0,0 +1,16 @@
# Localization
At Mozilla, localization refers to adapting the user interface and messages
to different cultural and regional needs. Localization is a broader term than
translation because it involves extensive research into the target culture, and
in result touches not only text and UI translation but also cultural adaptation
of icons, communication styles, colors, and UX.
Questions about Thunderbird localization should be directed to the Localization
Coordinator. Contact information is on the
[Thunderbird Project page in Pontoon](https://pontoon.mozilla.org/projects/thunderbird/info/).
```{toctree}
fluent_migrations
testing_migrations
```

Просмотреть файл

@ -0,0 +1,39 @@
# Testing Migration Recipes
## During Development
To test migration recipes during development, use the following mach command:
```bash
./mach tb-fluent-migration-test comm/python/l10n/tb_fluent_migrations/bug_1805746_calendar_view.py
```
This will analyze your migration recipe to check that the migrate function exists,
and interacts correctly with the migration context. Once that passes, it clones
`comm-strings-quarantine` into `$OBJDIR/comm/python/l10n`, creates a reference
localization by adding your local Fluent strings to the ones in
`comm-strings-quarantine` (essentially the first part of the cross-channel
process).
It then runs the migration recipe, both as dry run and as actual migration.
Finally it analyzes the commits, and checks if any migrations were actually run
and the bug number in the commit message matches the migration name.
It will also show the diff between the migrated files and the reference, ignoring
blank lines.
You can inspect the generated repository further by looking in
`$OBJDIR/comm/python/l10n/bug_1805746_calendar_view/en-US`.
## During Review
During l10n review, migration scripts will be run against all Thunderbird locales.
Any problems will be reported back to the author as part of the regular code
review process in Phabricator.
```{tip}
Plan on extra review time for migration scripts in case changes are needed.
Ask the Thunderbird L10n coordinator in [#maildev](https://matrix.to/#/#maildev:mozilla.org)
or your manager if you run into problems.
```

Просмотреть файл

@ -1,35 +0,0 @@
@ECHO OFF
pushd %~dp0
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build
%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)
if "%1" == "" goto help
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end
:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
:end
popd

Просмотреть файл

@ -1,3 +1,4 @@
Sphinx>=5,<6
sphinx_rtd_theme
myst-parser[linkify]
fluent.pygments>=1,<2

Просмотреть файл

@ -2,21 +2,25 @@
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
#
# pip-compile requirements.in
# pip-compile --resolver=backtracking requirements.in
#
alabaster==0.7.12
alabaster==0.7.13
# via sphinx
babel==2.11.0
# via sphinx
certifi==2022.12.7
# via requests
charset-normalizer==2.1.1
charset-normalizer==3.0.1
# via requests
docutils==0.17.1
# via
# myst-parser
# sphinx
# sphinx-rtd-theme
fluent-pygments==1.0
# via -r requirements.in
fluent-syntax==0.18.1
# via fluent-pygments
idna==3.4
# via requests
imagesize==1.4.1
@ -39,16 +43,20 @@ mdurl==0.1.2
# via markdown-it-py
myst-parser[linkify]==0.18.1
# via -r requirements.in
packaging==22.0
packaging==23.0
# via sphinx
pygments==2.13.0
# via sphinx
pytz==2022.6
pygments==2.14.0
# via
# fluent-pygments
# sphinx
pytz==2022.7
# via babel
pyyaml==6.0
# via myst-parser
requests==2.28.1
requests==2.28.2
# via sphinx
six==1.16.0
# via fluent-pygments
snowballstemmer==2.2.0
# via sphinx
sphinx==5.3.0
@ -58,7 +66,7 @@ sphinx==5.3.0
# sphinx-rtd-theme
sphinx-rtd-theme==1.1.1
# via -r requirements.in
sphinxcontrib-applehelp==1.0.2
sphinxcontrib-applehelp==1.0.3
# via sphinx
sphinxcontrib-devhelp==1.0.2
# via sphinx
@ -74,5 +82,5 @@ typing-extensions==4.4.0
# via myst-parser
uc-micro-py==1.0.1
# via linkify-it-py
urllib3==1.26.13
urllib3==1.26.14
# via requests

Просмотреть файл

@ -9,11 +9,9 @@ var EXPORTED_SYMBOLS = ["PromptParent"];
const lazy = {};
ChromeUtils.defineModuleGetter(
lazy,
"PromptUtils",
"resource://gre/modules/SharedPromptUtils.jsm"
);
ChromeUtils.defineESModuleGetters(lazy, {
PromptUtils: "resource://gre/modules/PromptUtils.sys.mjs",
});
/**
* @typedef {object} Prompt

Просмотреть файл

@ -188,8 +188,8 @@ var gBigFileObserver = {
} else if (accounts.length > 1) {
// We once used Services.prompt.select for this UI, but it doesn't support displaying an
// icon for each item. The following code does the same thing with a replacement dialog.
let { PromptUtils } = ChromeUtils.import(
"resource://gre/modules/SharedPromptUtils.jsm"
let { PromptUtils } = ChromeUtils.importESModule(
"resource://gre/modules/PromptUtils.sys.mjs"
);
let names = accounts.map(i => cloudFileAccounts.getDisplayName(i));

Просмотреть файл

@ -1 +1 @@
110.0a1
111.0a1

Просмотреть файл

@ -1 +1 @@
110.0a1
111.0a1

Просмотреть файл

@ -4,12 +4,6 @@
var EXPORTED_SYMBOLS = ["MsgAsyncPrompter", "MsgAuthPrompt"];
var { Deprecated } = ChromeUtils.importESModule(
"resource://gre/modules/Deprecated.sys.mjs"
);
const { PromptUtils } = ChromeUtils.import(
"resource://gre/modules/SharedPromptUtils.jsm"
);
var { XPCOMUtils } = ChromeUtils.importESModule(
"resource://gre/modules/XPCOMUtils.sys.mjs"
);
@ -22,6 +16,11 @@ const LoginInfo = Components.Constructor(
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
Deprecated: "resource://gre/modules/Deprecated.sys.mjs",
PromptUtils: "resource://gre/modules/PromptUtils.sys.mjs",
});
XPCOMUtils.defineLazyGetter(lazy, "dialogsBundle", function() {
return Services.strings.createBundle(
"chrome://global/locale/commonDialogs.properties"
@ -56,7 +55,7 @@ runnablePrompter.prototype = {
} catch (e) {
if (e.result == Cr.NS_ERROR_XPC_JSOBJECT_HAS_NO_FUNCTION_NAMED) {
// Fall back to onPromptStart, for add-ons compat
Deprecated.warning(
lazy.Deprecated.warning(
"onPromptStart has been replaced by onPromptStartAsync",
"https://bugzilla.mozilla.org/show_bug.cgi?id=1176399"
);
@ -551,7 +550,7 @@ function nsIPrompt_promptUsernameAndPassword(
ok: false,
};
let propBag = PromptUtils.objectToPropBag(args);
let propBag = lazy.PromptUtils.objectToPropBag(args);
Services.ww.openWindow(
Services.ww.activeWindow,
"chrome://global/content/commonDialog.xhtml",
@ -559,7 +558,7 @@ function nsIPrompt_promptUsernameAndPassword(
"centerscreen,chrome,modal,titlebar",
propBag
);
PromptUtils.propBagToObject(propBag, args);
lazy.PromptUtils.propBagToObject(propBag, args);
// Did user click Ok or Cancel?
let ok = args.ok;
@ -619,7 +618,7 @@ function nsIPrompt_promptPassword(
ok: false,
};
let propBag = PromptUtils.objectToPropBag(args);
let propBag = lazy.PromptUtils.objectToPropBag(args);
Services.ww.openWindow(
Services.ww.activeWindow,
"chrome://global/content/commonDialog.xhtml",
@ -627,7 +626,7 @@ function nsIPrompt_promptPassword(
"centerscreen,chrome,modal,titlebar",
propBag
);
PromptUtils.propBagToObject(propBag, args);
lazy.PromptUtils.propBagToObject(propBag, args);
// Did user click Ok or Cancel?
let ok = args.ok;

Просмотреть файл

@ -18,10 +18,7 @@ class nsMessengerWinIntegration : public nsIMessengerWindowsIntegration {
NS_DECL_ISUPPORTS
NS_DECL_NSIMESSENGERWINDOWSINTEGRATION
NS_IMETHOD UpdateUnreadCount(uint32_t unreadCount,
const nsAString& unreadTooltip);
NS_IMETHOD OnExit();
NS_DECL_NSIMESSENGEROSINTEGRATION
private:
static LRESULT CALLBACK IconWindowProc(HWND msgWindow, UINT msg, WPARAM wp,

Просмотреть файл

@ -1718,22 +1718,6 @@ nsMsgLocalMailFolder::CopyFileMessage(nsIFile* aFile, nsIMsgDBHdr* msgToReplace,
return rv;
}
nsresult nsMsgLocalMailFolder::DeleteMessage(nsISupports* message,
nsIMsgWindow* msgWindow,
bool deleteStorage, bool commit) {
nsresult rv = NS_OK;
if (deleteStorage) {
nsCOMPtr<nsIMsgDBHdr> msgDBHdr(do_QueryInterface(message, &rv));
if (NS_SUCCEEDED(rv)) {
GetDatabase();
if (mDatabase)
rv = mDatabase->DeleteHeader(msgDBHdr, nullptr, commit, true);
}
}
return rv;
}
NS_IMETHODIMP nsMsgLocalMailFolder::GetNewMessages(nsIMsgWindow* aWindow,
nsIUrlListener* aListener) {
nsCOMPtr<nsIMsgIncomingServer> server;

Просмотреть файл

@ -215,8 +215,6 @@ class nsMsgLocalMailFolder : public nsMsgDBFolder,
nsresult ConfirmFolderDeletion(nsIMsgWindow* aMsgWindow,
nsIMsgFolder* aFolder, bool* aResult);
nsresult DeleteMessage(nsISupports* message, nsIMsgWindow* msgWindow,
bool deleteStorage, bool commit);
nsresult GetDatabase() override;
// this will set mDatabase, if successful. It will also create a .msf file
// for an empty local mail folder. It will leave invalid DBs in place, and

Просмотреть файл

@ -1 +1 @@
2.107a1
2.108a1

Просмотреть файл

@ -1 +1 @@
2.107a1
2.108a1