Skip to content

Commit

Permalink
0.9.0
Browse files Browse the repository at this point in the history
  • Loading branch information
kgv committed Nov 12, 2023
1 parent 8c62112 commit 99454c8
Show file tree
Hide file tree
Showing 47 changed files with 374 additions and 595 deletions.
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bevy_fluent"
version = "0.8.0"
version = "0.9.0"
authors = ["g <[email protected]>"]
edition = "2021"
description = "Bevy plugin for localization using Fluent"
Expand All @@ -18,23 +18,23 @@ categories = [
exclude = [".github/**/*"]

[dependencies]
bevy = { version = "0.12", default-features = false, features = ["bevy_asset"] }
bevy = { version = "0.12.0", default-features = false, features = [
"bevy_asset",
] }
fluent = "0.16.0"
fluent_content = "0.0.5"
fluent-langneg = "0.13.0"
futures-lite = "2.0.0"
futures-lite = "2.0.1"
indexmap = { version = "2.1.0", features = ["serde"] }
intl-memoizer = "0.5.1"
ron = "0.8.1"
serde = { version = "1.0.188", features = ["derive"] }
serde = { version = "1.0.192", features = ["derive"] }
serde_yaml = "0.9.27"
thiserror = "1.0.50"
tracing = "0.1.40"
unic-langid = { version = "0.9.1", features = ["serde"] }
uuid = { version = "1.5.0", features = ["serde", "v4", "v5"] }
# fluent-syntax = { git = "https://github.com/projectfluent/fluent-rs" }
# globset = "0.4.13"

[dev-dependencies]
bevy = "0.12"
bevy = "0.12.0"
unic-langid = { version = "0.9.1", features = ["macros"] }
34 changes: 15 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

| bevy | bevy_fluent |
|------|-------------|
| 0.12 | 0.8 |
| 0.12 | 0.8, 0.9 |
| 0.11 | 0.7 |
| 0.10 | 0.6 |
| 0.9 | 0.5 |
Expand All @@ -25,38 +25,34 @@
## See Also

- [Bevy][bevy] ❤️
- [Bevy localisation plugin issue][bevy-localisation-plugin-issue]
- [Bevy localisation plugin issue](https://github.com/bevyengine/bevy/issues/461)

***

- [Fluent][fluent]
- [Fluent fallback][fluent-fallback]
- [Fluent language negotiation][fluent-langneg]
- [Fluent message format 2.0][fluent-message-format-2.0]
- [Fluent resource manager][fluent-resmgr]
- [L10nRegistry][l10nregistry]
- [Fluent fallback](https://github.com/projectfluent/fluent-rs/tree/master/fluent-fallback)
- [Fluent language negotiation](https://github.com/projectfluent/fluent-langneg-rs)
- [Fluent message format 2.0](https://github.com/zbraniecki/message-format-2.0-rs)
- [Fluent resource manager](https://github.com/projectfluent/fluent-rs/tree/master/fluent-resmgr)
- [L10nRegistry](https://github.com/zbraniecki/l10nregistry-rs)

***

- [Locales](https://github.com/unicode-org/cldr-json/blob/master/cldr-json/cldr-core/availableLocales.json)
- [Unicode Language Identifier][unicode-language-identifier]
- [Message format working group](https://github.com/unicode-org/message-format-wg)
- [Unicode Language Identifier](http://unicode.org/reports/tr35/#Unicode_language_identifier)
= [ICU4X](https://github.com/unicode-org/icu4x)

## Dedication

Thanks to my little sister Anny ❤️ the world's best linguist and the most
wonderful sister.

[bevy]: https://github.com/bevyengine/bevy
[bevy-localisation-plugin-issue]: https://github.com/bevyengine/bevy/issues/461
[fluent]: https://github.com/projectfluent/fluent-rs
[fluent-fallback]: https://github.com/projectfluent/fluent-rs/tree/master/fluent-fallback
[fluent-langneg]: https://github.com/projectfluent/fluent-langneg-rs
[fluent-message-format-2.0]: https://github.com/zbraniecki/message-format-2.0-rs
[fluent-resmgr]: https://github.com/projectfluent/fluent-rs/tree/master/fluent-resmgr
[l10nregistry]: https://github.com/zbraniecki/l10nregistry-rs
[unicode-language-identifier]: http://unicode.org/reports/tr35/#Unicode_language_identifier

[unic-locale]: https://docs.rs/unic-locale/0.9.0/unic_locale/index.html
[language-tags]: https://www.w3.org/International/questions/qa-choosing-language-tags.ru
[language-subtag-lookup]: https://r12a.github.io/app-subtags

[iana-language-subtag-registry]: http://www.iana.org/assignments/language-subtag-registry
[icu4x message-format 2]: https://github.com/unicode-org/icu4x/pull/2272
[language-subtag-lookup]: https://r12a.github.io/app-subtags
[language-tags]: https://www.w3.org/International/questions/qa-choosing-language-tags.ru
[unic-locale]: https://docs.rs/unic-locale/0.9.0/unic_locale/index.html
57 changes: 14 additions & 43 deletions doc/en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,7 @@
Load asset using `AssetServer`:

```rust
let handle = asset_server.load("locales/en-US/main.ftl.ron");
```

Load all assets matching the glob using `AssetServerExt`:

```rust
use bevy_fluent::exts::bevy::AssetServerExt;

let handles = asset_server.load_glob("locales/**/main.ftl.ron")?;
let handle = asset_server.load("locales/.ftl.ron#en-US");
```

Check assets load state:
Expand All @@ -26,52 +18,32 @@ if let LoadState::Loaded = asset_server.get_load_state(handle) {
}
```

Check assets load state:

```rust
if let LoadState::Loaded = asset_server.get_group_load_state(handles) {
...
}
```

Create a bundle fallback chain based on the locale fallback chain using
`LocalizationBuilder`:

```rust
let localization = localization_builder.build(handles);
```

Request content:

```rust
let hello_world = bundle_asset.content("hello-world")?;
let hello_world = localization.content("hello-world")?;
```

## Definitions
[`BundleAsset`][bundle-asset] - is an abstraction for presentation
[`FluentBundle`][fluent-bundle]. A *bundles* file has the extension `.ftl.ron`
or `.ftl.yml` and proper format. It contains information about all
`FluentBundle`s.

[***Localization***][localization] is a Fluent [***bundle***][fluent-bundle]
fallback chain.

[***Bundle asset***][bundle-asset] - is an abstraction for presentation Fluent
*bundles*. Each *bundle asset* file has the extension `.ftl.ron`.

[***Resource asset***][resource-asset] - is an abstraction for presentation
Fluent [***resources***][fluent-resource]. Each *resource asset* file has the
extension `.ftl`. *Resource asset* is the atomic unit of disk storage for
Fluent.
[`ResourceAsset`][resource-asset] - is an abstraction for presentation
[`FluentResource`][fluent-resource]. A *resource* file has the extension `.ftl`.

Each *resource asset* is a set of [***messages***][message]. *Message* is the
basic atomic translation unit for Fluent.
Each `ResourceAsset` is a set of [`Message`][message]s. `Message` is the basic
atomic translation unit for Fluent.

Each *message* has an [***identifier***][identifier].
Each `Message` has an [`Identifier`][identifier].

*Messages* (and [***terms***][term], [***variants***][variant],
[***attributes***][attribute]) store their values as [***patterns***][pattern].
`Message`s (and [`Term`][Term]s, [`Variant`][variant]s,
[`Attribute`][attribute]s) store their values as [`Pattern`][pattern]s.

Formated *pattern* are called [***content***][content].
Formated `Pattern` are called [`Content`][content].

[***Request***][request] is a request to receive *content* specified by the
[`Request`][request] is a request to receive `Content` specified by the
parameters.

[attribute]: https://docs.rs/fluent-syntax/*/fluent_syntax/ast/struct.Attribute.html
Expand All @@ -80,7 +52,6 @@ parameters.
[fluent-bundle]: https://docs.rs/fluent/*/fluent/bundle/struct.FluentBundle.html
[fluent-resource]: https://docs.rs/fluent/*/fluent/struct.FluentResource.html
[identifier]: https://docs.rs/fluent-syntax/*/fluent_syntax/ast/struct.Identifier.html
[localization]: https://docs.rs/bevy_fluent/*/bevy_fluent/assets/struct.Localization.html
[message]: https://docs.rs/fluent-syntax/*/fluent_syntax/ast/struct.Message.html
[pattern]: https://docs.rs/fluent-syntax/*/fluent_syntax/ast/struct.Pattern.html
[request]: https://docs.rs/bevy_fluent/*/bevy_fluent/exts/bundle/struct.Request.html
Expand Down
59 changes: 15 additions & 44 deletions doc/ru-RU.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,7 @@
Загрузить ассет с помощью `AssetServer`:

```rust
let handle = asset_server.load("locales/ru-RU/main.ftl.ron");
```

Загрузить все ассеты, удовлетворяющие шаблону, с помощью `AssetServerExt`:

```rust
use bevy_fluent::exts::bevy::AssetServerExt;

let handles = asset_server.load_glob("locales/**/main.ftl.ron")?;
let handle = asset_server.load("locales/.ftl.ron#ru-RU");
```

Проверить статус загрузки ассета:
Expand All @@ -26,62 +18,41 @@ if let LoadState::Loaded = asset_server.get_load_state(handle) {
}
```

Проверить статус загрузки нескольких ассетов:

```rust
if let LoadState::Loaded = asset_server.get_group_load_state(handles) {
...
}
```

Создать резервную цепочку бандлов на основе резервной цепочки локалей с помощью
`LocalizationBuilder`:

```rust
let localization = localization_builder.build(handles);
```

Запросить контент:

```rust
let hello_world = bundle_asset.content("hello-world")?;
let hello_world = localization.content("hello-world")?;
```

## Определения

[***Локализация***][localization] представляет собой резервную цепочку
[***бандлов***][fluent-bundle] Fluent.

[***Ассет бандла***][bundle-asset] - является абстракцией для представления
*бандлов* Fluent. Файл *ассета бандла* имеет расширение `.ftl.ron`.
[`BundleAsset`][bundle-asset] - является абстракцией для представления
[`FluentBundle`][fluent-bundle]. Файл *бандлов* имеет расширение `.ftl.ron` или
`.ftl.yml` и соответствующий формат. Он содержит информацию обо всех
`FluentBundle`.

[***Ассет ресурса***][resource-asset] - является абстракцией для представления
[***ресурсов***][fluent-resource] Fluent. Файл *ассета ресурсов* имеет
расширение `.ftl`. *Ассет ресурса* является атомарной единицей хранения
информации на диске для Fluent.
[`ResourceAsset`][resource-asset] - является абстракцией для представления
[`FluentResource`][fluent-resource]. Файл *ресурса* имеет расширение `.ftl`.

Каждый *ассет ресурса* представляет собой набор [***сообщений***][message].
*Cообщение* является атомарной единицей перевода во Fluent.
Каждый `ResourceAsset` представляет собой набор из [`Message`][message].
`Message` является атомарной единицей перевода во Fluent.

Каждое *сообщение* имеет [***идентификатор***][identifier].
Каждое `Message` имеет [`Identifier`][identifier].

*Сообщения* (как и [***термы***][term], [***варианты***][variant],
[***аттрибуты***][attribute]) хранят свои значения в виде
[***паттернов***][pattern].
`Message` (как и [`Term`][term], [`Variant`][variant], [`Attribute`][attribute])
хранят свои значения в виде [`Pattern`][pattern].

Форматированный *паттерн* называется [***контентом***][content].
Форматированный `Pattern` называется [`Content`][content].

[***Запрос***][request] представляет собой запрос на получение соответствующего
заданным параметрам *контента*.
[`Request`][request] представляет собой запрос на получение `Content`,
соответствующего заданным параметрам.

[attribute]: https://docs.rs/fluent-syntax/*/fluent_syntax/ast/struct.Attribute.html
[bundle-asset]: https://docs.rs/bevy_fluent/*/bevy_fluent/assets/struct.BundleAsset.html
[content]: https://docs.rs/bevy_fluent/*/bevy_fluent/exts/bundle/trait.BundleExt.html#tymethod.content
[fluent-bundle]: https://docs.rs/fluent/*/fluent/bundle/struct.FluentBundle.html
[fluent-resource]: https://docs.rs/fluent/*/fluent/struct.FluentResource.html
[identifier]: https://docs.rs/fluent-syntax/*/fluent_syntax/ast/struct.Identifier.html
[localization]: https://docs.rs/bevy_fluent/*/bevy_fluent/assets/struct.Localization.html
[message]: https://docs.rs/fluent-syntax/*/fluent_syntax/ast/struct.Message.html
[pattern]: https://docs.rs/fluent-syntax/*/fluent_syntax/ast/struct.Pattern.html
[request]: https://docs.rs/bevy_fluent/*/bevy_fluent/exts/bundle/struct.Request.html
Expand Down
5 changes: 5 additions & 0 deletions examples/fallback_chain/assets/locales/.ftl.ron
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"en-US": ["en-US/main.ftl"],
"ru-BY": ["ru/ru-BY/main.ftl"],
"ru-RU": ["ru/ru-RU/main.ftl"],
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
hello = hello
world = world
hello-world = hello world
bevy = bevy
6 changes: 0 additions & 6 deletions examples/fallback_chain/assets/locales/en-US/main.ftl.ron

This file was deleted.

6 changes: 0 additions & 6 deletions examples/fallback_chain/assets/locales/ru/ru-BY/main.ftl.ron

This file was deleted.

6 changes: 0 additions & 6 deletions examples/fallback_chain/assets/locales/ru/ru-RU/main.ftl.ron

This file was deleted.

49 changes: 30 additions & 19 deletions examples/fallback_chain/main.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,52 @@
use bevy::{
asset::{LoadState, LoadedFolder},
prelude::*,
};
use bevy_fluent::prelude::*;
use bevy::{asset::LoadState, prelude::*};
use bevy_fluent::{prelude::*, resources::Locales};
use fluent_content::Content;
use unic_langid::langid;

pub fn main() {
App::new()
.insert_resource(Locale::new(langid!("ru-RU")).with_default(langid!("en-US")))
.insert_resource(
Locales::new([langid!("en-US"), langid!("ru-RU"), langid!("ru-BY")])
.with_default(langid!("en-US")),
)
.add_plugins((
DefaultPlugins.set(AssetPlugin {
file_path: "examples/fallback_chain/assets".to_string(),
..default()
}),
FluentPlugin,
))
.add_systems(Update, localized_hello_world)
.add_systems(Update, localize)
.run();
}

fn localized_hello_world(
localization_builder: LocalizationBuilder,
fn localize(
locales: Res<Locales>,
asset_server: Res<AssetServer>,
mut handle: Local<Option<Handle<LoadedFolder>>>,
mut localization: Local<Option<Localization>>,
assets: Res<Assets<BundleAsset>>,
mut handles: Local<Option<Vec<Handle<BundleAsset>>>>,
mut bundles: Local<Bundles>,
) {
let handle = &*handle.get_or_insert_with(|| asset_server.load_folder("locales"));
if let Some(LoadState::Loaded) = asset_server.get_load_state(handle) {
let localization = localization.get_or_insert_with(|| localization_builder.build(handle));
let handles = handles.get_or_insert_with(|| {
locales
.request(Some(langid!("ru-RU")))
.iter()
.map(|locale| asset_server.load(format!("locales/.ftl.ron#{locale}")))
.collect()
});
if handles
.iter()
.all(|handle| asset_server.get_load_state(handle) == Some(LoadState::Loaded))
{
*bundles = handles
.iter()
.map(|handle| (handle.clone(), assets.get(handle).unwrap().clone()))
.collect();
// From ru-RU bundle, the first in fallback chain.
assert!(matches!(localization.content("hello"), Some(content) if content == "привет"));
assert!(matches!(bundles.content("hello"), Some(content) if content == "привет"));
// From ru-BY bundle, the second in fallback chain.
assert!(matches!(localization.content("world"), Some(content) if content == "свету"));
assert!(matches!(bundles.content("world"), Some(content) if content == "свету"));
// From en-US bundle, the last in fallback chain, default locale.
assert!(
matches!(localization.content("hello-world"), Some(content) if content == "hello world")
);
assert!(matches!(bundles.content("bevy"), Some(content) if content == "bevy"));
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
# Locale files may be in YAML as in this example, or in RON
locale: en-US
resources:
- hello_world.ftl
en-US: [en-US/main.ftl]
Loading

0 comments on commit 99454c8

Please sign in to comment.