diff --git a/CHANGELOG.md b/CHANGELOG.md index f05d774e61..e9eecd0e08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ For details about compatibility between different releases, see the **Commitment - `ListFrequencyPlans` RPC has a new `gateways-only` flag. - Option to pause application webhooks. - Endpoint for claiming gateways using a qr code +- Update the GetTemplate endpoint in device repository to check for profile identifiers in the vendor index. ### Changed diff --git a/config/messages.json b/config/messages.json index d7461ca92f..6c8e4924d3 100644 --- a/config/messages.json +++ b/config/messages.json @@ -4121,9 +4121,9 @@ "file": "store.go" } }, - "error:pkg/devicerepository/store/bleve:multiple_identifiers": { + "error:pkg/devicerepository/store/bleve:missing_profile_identifiers": { "translations": { - "en": "multiple identifiers found in the request. Use either EndDeviceVersionIdentifiers or EndDeviceProfileIdentifiers" + "en": "both vendor ID and vendor profile ID must be provided" }, "description": { "package": "pkg/devicerepository/store/bleve", @@ -4139,6 +4139,15 @@ "file": "remote.go" } }, + "error:pkg/devicerepository/store/remote:band_not_found_for_region": { + "translations": { + "en": "band not found for region `{region}`" + }, + "description": { + "package": "pkg/devicerepository/store/remote", + "file": "remote.go" + } + }, "error:pkg/devicerepository/store/remote:brand_not_found": { "translations": { "en": "brand `{brand_id}` not found" @@ -4148,6 +4157,15 @@ "file": "remote.go" } }, + "error:pkg/devicerepository/store/remote:brand_with_vendor_id_not_found": { + "translations": { + "en": "brand with vendor ID `{vendor_id}` not found" + }, + "description": { + "package": "pkg/devicerepository/store/remote", + "file": "remote.go" + } + }, "error:pkg/devicerepository/store/remote:firmware_version_not_found": { "translations": { "en": "firmware version `{firmware_version}` for model `{brand_id}/{model_id}` not found" @@ -4157,6 +4175,15 @@ "file": "remote.go" } }, + "error:pkg/devicerepository/store/remote:missing_profile_identifiers": { + "translations": { + "en": "both vendor ID and vendor profile ID must be provided" + }, + "description": { + "package": "pkg/devicerepository/store/remote", + "file": "remote.go" + } + }, "error:pkg/devicerepository/store/remote:model_not_found": { "translations": { "en": "model `{brand_id}/{model_id}` not found" @@ -4202,6 +4229,24 @@ "file": "remote.go" } }, + "error:pkg/devicerepository/store/remote:no_template_identifiers": { + "translations": { + "en": "one of version_ids or end_device_profile_ids must be set" + }, + "description": { + "package": "pkg/devicerepository/store/remote", + "file": "remote.go" + } + }, + "error:pkg/devicerepository/store/remote:vendor_profile_id_not_found": { + "translations": { + "en": "vendor profile ID `{vendor_profile_id}` not found for vendor ID `{vendor_id}`" + }, + "description": { + "package": "pkg/devicerepository/store/remote", + "file": "remote.go" + } + }, "error:pkg/devicerepository/store:regional_parameters_version": { "translations": { "en": "unknown Regional Parameters version `{phy_version}`" diff --git a/pkg/devicerepository/grpc.go b/pkg/devicerepository/grpc.go index bad776016a..07f179ac17 100644 --- a/pkg/devicerepository/grpc.go +++ b/pkg/devicerepository/grpc.go @@ -180,7 +180,7 @@ func (dr *DeviceRepository) GetTemplate( if err := rights.RequireAuthenticated(ctx); err != nil { return nil, err } - return dr.store.GetTemplate(req, nil) + return dr.store.GetTemplate(req) } func getDecoder( diff --git a/pkg/devicerepository/grpc_test.go b/pkg/devicerepository/grpc_test.go index 93517a1e50..a416dc8086 100644 --- a/pkg/devicerepository/grpc_test.go +++ b/pkg/devicerepository/grpc_test.go @@ -99,7 +99,6 @@ func (*mockStore) GetEndDeviceProfiles( // GetTemplate retrieves an end device template for an end device definition. func (s *mockStore) GetTemplate( req *ttnpb.GetTemplateRequest, - _ *store.EndDeviceProfile, ) (*ttnpb.EndDeviceTemplate, error) { s.lastVersionIDs = req.GetVersionIds() profileIDs := req.GetEndDeviceProfileIds() @@ -111,6 +110,12 @@ func (s *mockStore) GetTemplate( return s.template, s.err } +func (*mockStore) GetEndDeviceProfileIdentifiers( + _ store.GetEndDeviceProfileIdentifiersRequest, +) (*store.GetEndDeviceProfileIdentifiersResponse, error) { + return nil, nil //nolint:nilnil +} + // GetUplinkDecoder retrieves the codec for decoding uplink messages. func (s *mockStore) GetUplinkDecoder(req store.GetCodecRequest) (*ttnpb.MessagePayloadDecoder, error) { s.lastVersionIDs = req.GetVersionIds() diff --git a/pkg/devicerepository/store/bleve/bleve.go b/pkg/devicerepository/store/bleve/bleve.go index 52da8e9e79..8aa4f2c1e9 100644 --- a/pkg/devicerepository/store/bleve/bleve.go +++ b/pkg/devicerepository/store/bleve/bleve.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package bleve implements a Device Repository store with indexing capabilities +// using the bleve library. package bleve import ( @@ -29,12 +31,12 @@ import ( ) const ( - // defaultTimeout is the timeout when trying to open the index. This is to avoid - // blocking on the index open call, which hangs indefinitely if the index is - // already in use by a different process. + // DefaultTimeout for opening the index. This is to avoid blocking on the index + // open call, which hangs indefinitely if the index is already in use by + // a different process. defaultTimeout = 5 * time.Second - // cacheSize is the size of the cache for brands and models. + // CacheSize for brands and models. cacheSize = 1024 ) @@ -78,11 +80,11 @@ func (c Config) NewStore(ctx context.Context) (store.Store, error) { var errCannotOpenIndex = errors.DefineNotFound("cannot_open_index", "cannot open index") -func openIndex(ctx context.Context, path string) (bleve.Index, error) { - log.FromContext(ctx).WithField("path", path).Debug("Loading index") - index, err := bleve.OpenUsing(path, map[string]any{"read_only": true, "bolt_timeout": "60s"}) +func openIndex(ctx context.Context, indexPath string) (bleve.Index, error) { + log.FromContext(ctx).WithField("path", indexPath).Debug("Loading index") + index, err := bleve.OpenUsing(indexPath, map[string]any{"read_only": true, "bolt_timeout": "60s"}) if err != nil { - return nil, errCannotOpenIndex.WithAttributes("path", path).WithCause(err) + return nil, errCannotOpenIndex.WithAttributes("path", indexPath).WithCause(err) } return index, nil } diff --git a/pkg/devicerepository/store/bleve/bleve_test.go b/pkg/devicerepository/store/bleve/bleve_test.go index ead9d2562d..99f6ccdf7d 100644 --- a/pkg/devicerepository/store/bleve/bleve_test.go +++ b/pkg/devicerepository/store/bleve/bleve_test.go @@ -28,11 +28,15 @@ import ( ) func TestBleve(t *testing.T) { + t.Parallel() + a := assertions.New(t) if err := os.MkdirAll("testdata/data/lorawan-devices-index", 0o755); err != nil { panic(err) } - defer os.RemoveAll("testdata/data/lorawan-devices-index") + t.Cleanup(func() { + os.RemoveAll("testdata/data/lorawan-devices-index") + }) c := bleve.Config{ SearchPaths: []string{"testdata/data/lorawan-devices-index"}, } @@ -46,6 +50,8 @@ func TestBleve(t *testing.T) { } t.Run("GetBrands", func(t *testing.T) { + t.Parallel() + for _, tc := range []struct { name string request store.GetBrandsRequest @@ -113,7 +119,7 @@ func TestBleve(t *testing.T) { OrderBy: "brand_id", Paths: []string{"brand_id"}, }, - result: brandsResponse("foo-vendor", "full-vendor"), + result: brandsResponse("foo-vendor", "full-vendor", "windsensor-vendor"), }, { name: "OrderDesc", @@ -121,7 +127,7 @@ func TestBleve(t *testing.T) { OrderBy: "-brand_id", Paths: []string{"brand_id"}, }, - result: brandsResponse("full-vendor", "foo-vendor"), + result: brandsResponse("windsensor-vendor", "full-vendor", "foo-vendor"), }, { name: "Limit", @@ -130,7 +136,7 @@ func TestBleve(t *testing.T) { Paths: []string{"brand_id"}, }, result: &store.GetBrandsResponse{ - Total: 2, + Total: 3, Count: 1, Brands: []*ttnpb.EndDeviceBrand{{BrandId: "foo-vendor"}}, }, @@ -143,7 +149,7 @@ func TestBleve(t *testing.T) { Paths: []string{"brand_id"}, }, result: &store.GetBrandsResponse{ - Total: 2, + Total: 3, Offset: 1, Count: 1, Brands: []*ttnpb.EndDeviceBrand{{BrandId: "full-vendor"}}, @@ -188,7 +194,7 @@ func TestBleve(t *testing.T) { Search: "ETSI", Paths: []string{"brand_id"}, }, - result: brandsResponse("full-vendor"), + result: brandsResponse("full-vendor", "windsensor-vendor"), }, } { t.Run(tc.name, func(t *testing.T) { @@ -205,6 +211,8 @@ func TestBleve(t *testing.T) { }) t.Run("GetModels", func(t *testing.T) { + t.Parallel() + for _, tc := range []struct { name string request store.GetModelsRequest @@ -240,7 +248,7 @@ func TestBleve(t *testing.T) { OrderBy: "model_id", Paths: []string{"model_id"}, }, - result: modelsResponse("dev1", "dev2", "full-device"), + result: modelsResponse("dev1", "dev2", "full-device", "windsensor"), }, { name: "OrderDesc", @@ -248,7 +256,7 @@ func TestBleve(t *testing.T) { OrderBy: "-model_id", Paths: []string{"model_id"}, }, - result: modelsResponse("full-device", "dev2", "dev1"), + result: modelsResponse("windsensor", "full-device", "dev2", "dev1"), }, { name: "Offset", @@ -261,9 +269,9 @@ func TestBleve(t *testing.T) { result: &store.GetModelsResponse{ Count: 1, Offset: 1, - Total: 3, + Total: 4, Models: []*ttnpb.EndDeviceModel{{ - ModelId: "dev2", + ModelId: "full-device", }}, }, }, @@ -332,7 +340,7 @@ func TestBleve(t *testing.T) { OrderBy: "model_id", Paths: []string{"model_id"}, }, - result: modelsResponse("dev2", "full-device"), + result: modelsResponse("dev2", "full-device", "windsensor"), }, { name: "SearchByPartNumber", @@ -348,7 +356,7 @@ func TestBleve(t *testing.T) { Search: "ETSI", Paths: []string{"model_id"}, }, - result: modelsResponse("full-device"), + result: modelsResponse("full-device", "windsensor"), }, } { t.Run(tc.name, func(t *testing.T) { @@ -365,7 +373,10 @@ func TestBleve(t *testing.T) { }) t.Run("GetTemplate", func(t *testing.T) { + t.Parallel() + t.Run("Missing", func(t *testing.T) { + t.Parallel() a := assertions.New(t) for _, ids := range []*ttnpb.EndDeviceVersionIdentifiers{ @@ -390,13 +401,14 @@ func TestBleve(t *testing.T) { } { tmpl, err := s.GetTemplate(&ttnpb.GetTemplateRequest{ VersionIds: ids, - }, nil) + }) a.So(errors.IsNotFound(err), should.BeTrue) a.So(tmpl, should.BeNil) } }) t.Run("Success", func(t *testing.T) { + t.Parallel() a := assertions.New(t) tmpl, err := s.GetTemplate(&ttnpb.GetTemplateRequest{ VersionIds: &ttnpb.EndDeviceVersionIdentifiers{ @@ -406,13 +418,15 @@ func TestBleve(t *testing.T) { HardwareVersion: "2.0", BandId: "EU_433", }, - }, nil) + }) a.So(err, should.BeNil) a.So(tmpl, should.NotBeNil) }) }) t.Run("GetTemplateByNumericIDs", func(t *testing.T) { + t.Parallel() + for _, tc := range []struct { Name string Req *ttnpb.GetTemplateRequest @@ -424,7 +438,8 @@ func TestBleve(t *testing.T) { Name: "UnknownVendorID", Req: &ttnpb.GetTemplateRequest{ EndDeviceProfileIds: &ttnpb.GetTemplateRequest_EndDeviceProfileIdentifiers{ - VendorId: 2, + VendorId: 125, + VendorProfileId: 1, }, }, Assertion: func(t *ttnpb.EndDeviceTemplate, err error) bool { @@ -451,41 +466,15 @@ func TestBleve(t *testing.T) { }, }, Assertion: func(t *ttnpb.EndDeviceTemplate, err error) bool { - if !(a.So(t, should.NotBeNil) && a.So(err, should.BeNil)) { - return false - } - return a.So(t, should.Resemble, &ttnpb.EndDeviceTemplate{ - EndDevice: &ttnpb.EndDevice{ - VersionIds: &ttnpb.EndDeviceVersionIdentifiers{ - BrandId: "foo-vendor", - }, - LorawanVersion: ttnpb.MACVersion_MAC_V1_0_2, - LorawanPhyVersion: ttnpb.PHYVersion_PHY_V1_0_2_REV_B, - SupportsJoin: true, - MacSettings: &ttnpb.MACSettings{ - Supports_32BitFCnt: &ttnpb.BoolValue{ - Value: true, - }, - }, - }, - FieldMask: ttnpb.FieldMask( - "version_ids", - "supports_join", - "supports_class_b", - "supports_class_c", - "lorawan_version", - "lorawan_phy_version", - "mac_settings.supports_32_bit_f_cnt", - ), - }) + return a.So(errors.IsInvalidArgument(err), should.BeTrue) && a.So(t, should.BeNil) }, }, { Name: "SuccessfulFetch", Req: &ttnpb.GetTemplateRequest{ EndDeviceProfileIds: &ttnpb.GetTemplateRequest_EndDeviceProfileIdentifiers{ - VendorId: 42, - VendorProfileId: 3, + VendorId: 43, + VendorProfileId: 1, }, }, Assertion: func(t *ttnpb.EndDeviceTemplate, err error) bool { @@ -495,16 +484,25 @@ func TestBleve(t *testing.T) { return a.So(t, should.Resemble, &ttnpb.EndDeviceTemplate{ EndDevice: &ttnpb.EndDevice{ VersionIds: &ttnpb.EndDeviceVersionIdentifiers{ - BrandId: "foo-vendor", + BrandId: "windsensor-vendor", + ModelId: "windsensor", + FirmwareVersion: "1.0", + HardwareVersion: "1.0", + BandId: "EU_863_870", }, LorawanVersion: ttnpb.MACVersion_MAC_V1_0_3, LorawanPhyVersion: ttnpb.PHYVersion_PHY_V1_0_3_REV_A, SupportsJoin: true, + SupportsClassB: true, MacSettings: &ttnpb.MACSettings{ Supports_32BitFCnt: &ttnpb.BoolValue{ Value: true, }, }, + Formatters: &ttnpb.MessagePayloadFormatters{ + UpFormatter: ttnpb.PayloadFormatter_FORMATTER_REPOSITORY, + DownFormatter: ttnpb.PayloadFormatter_FORMATTER_REPOSITORY, + }, }, FieldMask: ttnpb.FieldMask( "version_ids", @@ -513,6 +511,7 @@ func TestBleve(t *testing.T) { "supports_class_c", "lorawan_version", "lorawan_phy_version", + "formatters", "mac_settings.supports_32_bit_f_cnt", ), }) @@ -520,7 +519,7 @@ func TestBleve(t *testing.T) { }, } { t.Run(tc.Name, func(t *testing.T) { - tmpl, err := s.GetTemplate(tc.Req, tc.EndDeviceProfile) + tmpl, err := s.GetTemplate(tc.Req) if !a.So(tc.Assertion(tmpl, err), should.BeTrue) { t.FailNow() } @@ -529,7 +528,10 @@ func TestBleve(t *testing.T) { }) t.Run("TestGetCodecs", func(t *testing.T) { + t.Parallel() + t.Run("Missing", func(t *testing.T) { + t.Parallel() a := assertions.New(t) for _, ids := range []*ttnpb.EndDeviceVersionIdentifiers{ diff --git a/pkg/devicerepository/store/bleve/init.go b/pkg/devicerepository/store/bleve/init.go index 6a19ec4ed7..7f5d9e13b9 100644 --- a/pkg/devicerepository/store/bleve/init.go +++ b/pkg/devicerepository/store/bleve/init.go @@ -35,10 +35,10 @@ import ( ) const ( - indexPath = "index.bleve" - brandDocumentType = "brand" - modelDocumentType = "model" - profileDocumentType = "profile" + indexPath = "index.bleve" + brandDocumentType = "brand" + modelDocumentType = "model" + templateDocumentType = "template" ) type indexableBrand struct { @@ -61,35 +61,34 @@ type indexableModel struct { Type string // Index document type, always modelDocumentType } -type indexableProfile struct { - Brand *ttnpb.EndDeviceBrand - Profile *store.EndDeviceProfile +type indexableTemplate struct { + Template *ttnpb.EndDeviceTemplate - ProfileJSON string // *store.EndDeviceProfile marshaled into string. - BrandID, VendorID, VendorProfileID string // stored separately to support queries. + TemplateJSON string // *ttnpb.EndDeviceTemplate marshaled into string. + VendorID, VendorProfileID string // stored separately to support queries. - Type string // Index document type, always profileDocumentType + Type string // Index document type, always templateDocumentType } -func newIndex(path string, overwrite bool, keywords ...string) (bleve.Index, error) { +func newIndex(indexPath string, overwrite bool, keywords ...string) (bleve.Index, error) { mapping := bleve.NewIndexMapping() - if st, err := os.Stat(path); err == nil && st.IsDir() && overwrite { - if err := os.RemoveAll(path); err != nil { + if st, err := os.Stat(indexPath); err == nil && st.IsDir() && overwrite { + if err := os.RemoveAll(indexPath); err != nil { return nil, err } } keywordFieldMapping := bleve.NewTextFieldMapping() keywordFieldMapping.Analyzer = keyword.Name - for _, keyword := range keywords { - mapping.DefaultMapping.AddFieldMappingsAt(keyword, keywordFieldMapping) + for _, k := range keywords { + mapping.DefaultMapping.AddFieldMappingsAt(k, keywordFieldMapping) } - return bleve.New(path, mapping) + return bleve.New(indexPath, mapping) } func getWorkingDirectory(paths []string) (string, error) { - for _, path := range paths { - if s, err := os.Stat(path); err == nil && s.IsDir() { - return path, nil + for _, p := range paths { + if s, err := os.Stat(p); err == nil && s.IsDir() { + return p, nil } } @@ -102,7 +101,7 @@ func getWorkingDirectory(paths []string) (string, error) { } // Initialize fetches the Device Repository package file and generates index files. -func (c Config) Initialize(ctx context.Context, lorawanDevicesPath string, overwrite bool) error { +func (c Config) Initialize(ctx context.Context, lorawanDevicesPath string, overwrite bool) error { //nolint:gocyclo wd, err := getWorkingDirectory(c.SearchPaths) if err != nil { return err @@ -133,20 +132,14 @@ func (c Config) Initialize(ctx context.Context, lorawanDevicesPath string, overw Paths: ttnpb.EndDeviceModelFieldPathsNested, BrandID: brand.BrandId, }) - if err != nil { - if errors.IsNotFound(err) { - // Skip vendors without any models - continue - } else { - return err - } + if errors.IsNotFound(err) { + // Skip vendors without any models. + continue } - profiles, err := s.GetEndDeviceProfiles(store.GetEndDeviceProfilesRequest{ - BrandID: brand.BrandId, - }) - if err != nil && !errors.IsNotFound(err) { + if err != nil { return err } + brandJSON, err := jsonpb.TTN().Marshal(brand) if err != nil { return err @@ -179,25 +172,49 @@ func (c Config) Initialize(ctx context.Context, lorawanDevicesPath string, overw return err } } - // Add the end device profiles to the index. + profiles, err := s.GetEndDeviceProfiles(store.GetEndDeviceProfilesRequest{ + BrandID: brand.BrandId, + }) + if err != nil && !errors.IsNotFound(err) { + return err + } + // Add the end device templates to the index. if profiles != nil { for _, profile := range profiles.Profiles { - profileJSON, err := jsonpb.TTN().Marshal(profile) + // Skip profiles without complete information. + if brand.LoraAllianceVendorId == 0 || profile.VendorProfileID == 0 { + continue + } + + vendorID := strconv.Itoa(int(brand.LoraAllianceVendorId)) + vendorProfileID := strconv.Itoa(int(profile.VendorProfileID)) + + template, err := s.GetTemplate(&ttnpb.GetTemplateRequest{ + EndDeviceProfileIds: &ttnpb.GetTemplateRequest_EndDeviceProfileIdentifiers{ + VendorId: brand.LoraAllianceVendorId, + VendorProfileId: profile.VendorProfileID, + }, + }) + if errors.IsNotFound(err) { + continue + } if err != nil { return err } - vendorProfileID := strconv.Itoa(int(profile.VendorProfileID)) - vendorID := strconv.Itoa(int(brand.LoraAllianceVendorId)) - p := indexableProfile{ - Type: profileDocumentType, - ProfileJSON: string(profileJSON), - Brand: brand, - Profile: profile, - BrandID: brand.BrandId, + + templateJSON, err := jsonpb.TTN().Marshal(template) + if err != nil { + return err + } + + t := indexableTemplate{ + Type: templateDocumentType, + TemplateJSON: string(templateJSON), + Template: template, VendorID: vendorID, VendorProfileID: vendorProfileID, } - if err := batch.Index(fmt.Sprintf("%s:%s", vendorID, vendorProfileID), p); err != nil { + if err := batch.Index(fmt.Sprintf("%s:%s", vendorID, vendorProfileID), t); err != nil { return err } } diff --git a/pkg/devicerepository/store/bleve/store.go b/pkg/devicerepository/store/bleve/store.go index 06a3a76138..a19258c226 100644 --- a/pkg/devicerepository/store/bleve/store.go +++ b/pkg/devicerepository/store/bleve/store.go @@ -28,10 +28,22 @@ import ( ) var ( - errCorruptedIndex = errors.DefineCorruption("corrupted_index", "corrupted index file") - errInvalidNumberOfProfiles = errors.DefineCorruption("invalid_number_of_profiles", "invalid number of profiles returned") - errMultipleIdentifiers = errors.DefineCorruption("multiple_identifiers", "multiple identifiers found in the request. Use either EndDeviceVersionIdentifiers or EndDeviceProfileIdentifiers") - errEndDeviceProfileNotFound = errors.DefineNotFound("end_device_profile_not_found", "end device profile not found for vendor ID `{vendor_id}` and vendor profile ID `{vendor_profile_id}`") + errCorruptedIndex = errors.DefineCorruption( + "corrupted_index", + "corrupted index file", + ) + errInvalidNumberOfProfiles = errors.DefineCorruption( + "invalid_number_of_profiles", + "invalid number of profiles returned", + ) + errEndDeviceProfileNotFound = errors.DefineNotFound( + "end_device_profile_not_found", + "end device profile not found for vendor ID `{vendor_id}` and vendor profile ID `{vendor_profile_id}`", + ) + errMissingProfileIdentifiers = errors.DefineInvalidArgument( + "missing_profile_identifiers", + "both vendor ID and vendor profile ID must be provided", + ) ) // retrieve returns the resulting document from the cache, if available. Otherwise, @@ -66,9 +78,9 @@ func (s *bleveStore) GetBrands(req store.GetBrandsRequest) (*store.GetBrandsResp queries = append(queries, bleve.NewQueryStringQuery(q)) } if q := req.BrandID; q != "" { - query := bleve.NewTermQuery(q) - query.SetField("BrandID") - queries = append(queries, query) + termQuery := bleve.NewTermQuery(q) + termQuery.SetField("BrandID") + queries = append(queries, termQuery) } searchRequest := bleve.NewSearchRequest(bleve.NewConjunctionQuery(queries...)) @@ -110,9 +122,9 @@ func (s *bleveStore) GetBrands(req store.GetBrandsRequest) (*store.GetBrandsResp brands = append(brands, pb) } return &store.GetBrandsResponse{ - Count: uint32(len(result.Hits)), - Total: uint32(result.Total), - Offset: uint32(searchRequest.From), + Count: uint32(len(result.Hits)), //nolint:gosec + Total: uint32(result.Total), //nolint:gosec + Offset: uint32(searchRequest.From), //nolint:gosec Brands: brands, }, nil } @@ -127,14 +139,14 @@ func (s *bleveStore) GetModels(req store.GetModelsRequest) (*store.GetModelsResp queries = append(queries, bleve.NewQueryStringQuery(q)) } if q := req.BrandID; q != "" { - query := bleve.NewTermQuery(q) - query.SetField("BrandID") - queries = append(queries, query) + queryTerm := bleve.NewTermQuery(q) + queryTerm.SetField("BrandID") + queries = append(queries, queryTerm) } if q := req.ModelID; q != "" { - query := bleve.NewTermQuery(q) - query.SetField("ModelID") - queries = append(queries, query) + queryTerm := bleve.NewTermQuery(q) + queryTerm.SetField("ModelID") + queries = append(queries, queryTerm) } searchRequest := bleve.NewSearchRequest(bleve.NewConjunctionQuery(queries...)) @@ -176,71 +188,63 @@ func (s *bleveStore) GetModels(req store.GetModelsRequest) (*store.GetModelsResp models = append(models, pb) } return &store.GetModelsResponse{ - Count: uint32(len(result.Hits)), - Total: uint32(result.Total), - Offset: uint32(searchRequest.From), + Count: uint32(len(result.Hits)), //nolint:gosec + Total: uint32(result.Total), //nolint:gosec + Offset: uint32(searchRequest.From), //nolint:gosec Models: models, }, nil } // GetTemplate retrieves an end device template for an end device definition. -func (s *bleveStore) GetTemplate(req *ttnpb.GetTemplateRequest, _ *store.EndDeviceProfile) (*ttnpb.EndDeviceTemplate, error) { - var ( - profile *store.EndDeviceProfile - endDeviceProfileIds = req.GetEndDeviceProfileIds() - ) - if endDeviceProfileIds != nil && req.VersionIds != nil { - return nil, errMultipleIdentifiers.New() +func (s *bleveStore) GetTemplate(req *ttnpb.GetTemplateRequest) (*ttnpb.EndDeviceTemplate, error) { + profileIDs := req.GetEndDeviceProfileIds() + if profileIDs == nil { + return s.store.GetTemplate(req) } - // Attempt to fetch the end device profile that matches the identifiers. - if endDeviceProfileIds != nil { - documentTypeQuery := bleve.NewTermQuery(profileDocumentType) - documentTypeQuery.SetField("Type") - queries := []query.Query{documentTypeQuery} - if q := endDeviceProfileIds.VendorId; q != 0 { - query := bleve.NewTermQuery(strconv.Itoa(int(q))) - query.SetField("VendorID") - queries = append(queries, query) - } - query := bleve.NewTermQuery(strconv.Itoa(int(endDeviceProfileIds.VendorProfileId))) - query.SetField("VendorProfileID") - queries = append(queries, query) + if profileIDs.VendorId == 0 || profileIDs.VendorProfileId == 0 { + return nil, errMissingProfileIdentifiers.New() + } + documentTypeQuery := bleve.NewTermQuery(templateDocumentType) + documentTypeQuery.SetField("Type") + queries := []query.Query{documentTypeQuery} - searchRequest := bleve.NewSearchRequest(bleve.NewConjunctionQuery(queries...)) - searchRequest.Fields = []string{"ProfileJSON", "BrandID"} - result, err := s.index.Search(searchRequest) - if err != nil { - return nil, err - } + queryTerm := bleve.NewTermQuery(strconv.Itoa(int(profileIDs.VendorId))) + queryTerm.SetField("VendorID") + queries = append(queries, queryTerm) - if len(result.Hits) == 0 { - return nil, errEndDeviceProfileNotFound.WithAttributes( - "vendor_id", endDeviceProfileIds.VendorId, - "vendor_profile_id", endDeviceProfileIds.VendorProfileId) - } + queryTerm = bleve.NewTermQuery(strconv.Itoa(int(profileIDs.VendorProfileId))) + queryTerm.SetField("VendorProfileID") + queries = append(queries, queryTerm) - if len(result.Hits) != 1 { - // There can only be one profile for a given tuple. - return nil, errInvalidNumberOfProfiles.New() - } + searchRequest := bleve.NewSearchRequest(bleve.NewConjunctionQuery(queries...)) + searchRequest.Fields = []string{"TemplateJSON"} + result, err := s.index.Search(searchRequest) + if err != nil { + return nil, err + } - brandID, ok := result.Hits[0].Fields["BrandID"].(string) - if !ok { - return nil, errCorruptedIndex.New() - } - // Set the Brand ID. - req.VersionIds = &ttnpb.EndDeviceVersionIdentifiers{ - BrandId: brandID, - } + if len(result.Hits) == 0 { + return nil, errEndDeviceProfileNotFound.WithAttributes( + "vendor_id", profileIDs.VendorId, + "vendor_profile_id", profileIDs.VendorProfileId) + } - model, err := s.retrieve(result.Hits[0], "ProfileJSON", func() any { return &store.EndDeviceProfile{} }) - if err != nil { - return nil, err - } - profile = model.(*store.EndDeviceProfile) + if len(result.Hits) != 1 { + // There can only be one profile for a given tuple. + return nil, errInvalidNumberOfProfiles.New() } - return s.store.GetTemplate(req, profile) + hit, err := s.retrieve(result.Hits[0], "TemplateJSON", func() any { return &ttnpb.EndDeviceTemplate{} }) + if err != nil { + return nil, err + } + + template, ok := hit.(*ttnpb.EndDeviceTemplate) + if !ok { + return nil, errCorruptedIndex.New() + } + + return template, nil } // GetUplinkDecoder retrieves the codec for decoding uplink messages. @@ -259,10 +263,19 @@ func (s *bleveStore) GetDownlinkEncoder(req store.GetCodecRequest) (*ttnpb.Messa } // GetEndDeviceProfiles implements store. -func (s *bleveStore) GetEndDeviceProfiles(req store.GetEndDeviceProfilesRequest) (*store.GetEndDeviceProfilesResponse, error) { +func (s *bleveStore) GetEndDeviceProfiles( + req store.GetEndDeviceProfilesRequest, +) (*store.GetEndDeviceProfilesResponse, error) { return s.store.GetEndDeviceProfiles(req) } +// GetEndDeviceProfileIdentifiers implements store. +func (s *bleveStore) GetEndDeviceProfileIdentifiers( + req store.GetEndDeviceProfileIdentifiersRequest, +) (*store.GetEndDeviceProfileIdentifiersResponse, error) { + return s.store.GetEndDeviceProfileIdentifiers(req) +} + // Close closes the store. func (s *bleveStore) Close() error { return s.index.Close() diff --git a/pkg/devicerepository/store/interface.go b/pkg/devicerepository/store/interface.go index 1ce8dc32c8..348fc09494 100644 --- a/pkg/devicerepository/store/interface.go +++ b/pkg/devicerepository/store/interface.go @@ -48,6 +48,16 @@ type GetModelsRequest struct { Search string } +// GetEndDeviceProfileIdentifiersRequest is used to retrieve end device profile identifiers. +type GetEndDeviceProfileIdentifiersRequest struct { + BrandID string +} + +// GetEndDeviceProfileIdentifiersResponse contains the end device profile identifiers. +type GetEndDeviceProfileIdentifiersResponse struct { + EndDeviceProfileIdentifiers []*EndDeviceProfileIdentifiers +} + // GetEndDeviceProfilesRequest is a request to list available LoRaWAN end device profile definitions. type GetEndDeviceProfilesRequest struct { BrandID, @@ -87,10 +97,12 @@ type Store interface { GetBrands(GetBrandsRequest) (*GetBrandsResponse, error) // GetModels lists available end device definitions. GetModels(GetModelsRequest) (*GetModelsResponse, error) + // GetEndDeviceProfileIdentifiers retrieves end device profile identifiers from the vendor index file. + GetEndDeviceProfileIdentifiers(GetEndDeviceProfileIdentifiersRequest) (*GetEndDeviceProfileIdentifiersResponse, error) // GetEndDeviceProfiles lists available LoRaWAN end device profile definitions. GetEndDeviceProfiles(GetEndDeviceProfilesRequest) (*GetEndDeviceProfilesResponse, error) // GetTemplate retrieves an end device template for an end device definition. - GetTemplate(*ttnpb.GetTemplateRequest, *EndDeviceProfile) (*ttnpb.EndDeviceTemplate, error) + GetTemplate(*ttnpb.GetTemplateRequest) (*ttnpb.EndDeviceTemplate, error) // GetUplinkDecoder retrieves the codec for decoding uplink messages. GetUplinkDecoder(GetCodecRequest) (*ttnpb.MessagePayloadDecoder, error) // GetDownlinkDecoder retrieves the codec for decoding downlink messages. diff --git a/pkg/devicerepository/store/profiles.go b/pkg/devicerepository/store/profiles.go index 05fa99700e..63ace1c72f 100644 --- a/pkg/devicerepository/store/profiles.go +++ b/pkg/devicerepository/store/profiles.go @@ -40,6 +40,20 @@ var regionalParametersToPB = map[string]ttnpb.PHYVersion{ "RP002-1.0.4": ttnpb.PHYVersion_RP002_V1_0_4, } +// EndDeviceProfileIdentifiers contains the profile identifiers of a LoRaWAN end device that +// is mentioned in the vendor index file (not embedded in the device model). +type EndDeviceProfileIdentifiers struct { + VendorProfileID string `yaml:"vendorProfileID"` + // First profile format. + EndDeviceID string `yaml:"endDeviceID"` + FirmwareVersion string `yaml:"firmwareVersion"` + HardwareVersion string `yaml:"hardwareVersion"` + Region string `yaml:"region"` + // Second profile format. + ProfileID string `yaml:"id"` + Codec string `yaml:"codec"` +} + // EndDeviceProfile is the profile of a LoRaWAN end device as defined in the LoRaWAN backend interfaces. type EndDeviceProfile struct { VendorProfileID uint32 `yaml:"vendorProfileID" json:"vendor_profile_id"` diff --git a/pkg/devicerepository/store/remote/remote.go b/pkg/devicerepository/store/remote/remote.go index 113a3aa6b7..ea11dba6ae 100644 --- a/pkg/devicerepository/store/remote/remote.go +++ b/pkg/devicerepository/store/remote/remote.go @@ -12,9 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Package remote implements a remote store for the Device Repository. package remote import ( + "fmt" + "strconv" + "go.thethings.network/lorawan-stack/v3/pkg/devicerepository/store" "go.thethings.network/lorawan-stack/v3/pkg/errors" "go.thethings.network/lorawan-stack/v3/pkg/fetch" @@ -36,12 +40,12 @@ func NewRemoteStore(fetcher fetch.Interface) store.Store { } // paginate returns page start and end indices, and false if the page is invalid. -func paginate(size int, limit, page uint32) (uint32, uint32) { +func paginate(size int, limit, page uint32) (start uint32, end uint32) { if page == 0 { page = 1 } offset := (page - 1) * limit - start, end := offset, uint32(size) + start, end = offset, uint32(size) //nolint:gosec if start >= end { return 0, 0 } @@ -79,7 +83,7 @@ func (s *remoteStore) GetBrands(req store.GetBrandsRequest) (*store.GetBrandsRes return &store.GetBrandsResponse{ Count: end - start, Offset: start, - Total: uint32(len(brands)), + Total: uint32(len(brands)), //nolint:gosec Brands: brands[start:end], }, nil } @@ -121,7 +125,7 @@ func (s *remoteStore) listModelsByBrand(req store.GetModelsRequest) (*store.GetM return &store.GetModelsResponse{ Count: end - start, Offset: start, - Total: uint32(len(index.EndDevices)), + Total: uint32(len(index.EndDevices)), //nolint:gosec Models: models, }, nil } @@ -157,13 +161,15 @@ func (s *remoteStore) GetModels(req store.GetModelsRequest) (*store.GetModelsRes return &store.GetModelsResponse{ Count: end - start, Offset: start, - Total: uint32(len(all)), + Total: uint32(len(all)), //nolint:gosec Models: all[start:end], }, nil } // getEndDeviceProfilesByBrand lists the available LoRaWAN end device profiles by a single brand. -func (s *remoteStore) getEndDeviceProfilesByBrand(req store.GetEndDeviceProfilesRequest) (*store.GetEndDeviceProfilesResponse, error) { +func (s *remoteStore) getEndDeviceProfilesByBrand( + req store.GetEndDeviceProfilesRequest, +) (*store.GetEndDeviceProfilesResponse, error) { b, err := s.fetcher.File("vendor", req.BrandID, "index.yaml") if err != nil { return nil, errBrandNotFound.WithAttributes("brand_id", req.BrandID) @@ -174,8 +180,7 @@ func (s *remoteStore) getEndDeviceProfilesByBrand(req store.GetEndDeviceProfiles } start, end := paginate(len(index.EndDevices), req.Limit, req.Page) - profiles := make([]*store.EndDeviceProfile, 0, end-start) - + profilesMap := make(map[string]*store.EndDeviceProfile, end-start) for idx := start; idx < end; idx++ { modelID := index.EndDevices[idx] if req.ModelID != "" && modelID != req.ModelID { @@ -192,8 +197,8 @@ func (s *remoteStore) getEndDeviceProfilesByBrand(req store.GetEndDeviceProfiles // For each profile ID, get the profile. for _, fwVersion := range model.FirmwareVersions { - for _, profile := range fwVersion.Profiles { - p, err := s.fetcher.File("vendor", req.BrandID, profile.ID+".yaml") + for region, profileInfo := range fwVersion.Profiles { + p, err := s.fetcher.File("vendor", req.BrandID, profileInfo.ID+".yaml") if err != nil { return nil, err } @@ -201,22 +206,78 @@ func (s *remoteStore) getEndDeviceProfilesByBrand(req store.GetEndDeviceProfiles if err := yaml.Unmarshal(p, &profile); err != nil { return nil, err } - profiles = append(profiles, &profile) + profileKey := s.buildProfileKey(modelID, fwVersion.Version, region) + profilesMap[profileKey] = &profile } } } + + // Append vendor profile IDs to the profiles. + if err := s.appendVendorProfileID(profilesMap, index); err != nil { + return nil, err + } + + profilesList := make([]*store.EndDeviceProfile, 0, len(profilesMap)) + for _, profile := range profilesMap { + profilesList = append(profilesList, profile) + } + return &store.GetEndDeviceProfilesResponse{ Count: end - start, Offset: start, - Total: uint32(len(index.EndDevices)), - Profiles: profiles, + Total: uint32(len(index.EndDevices)), //nolint:gosec + Profiles: profilesList, }, nil } +// appendVendorProfileID checks the vendor index for profile identifiers. If any identifiers +// are found, the vendor profile ID is set on the profile. The identifiers can be specified +// as a combination of either device ID + hardware version + firmware version + region, or +// profile ID + codec ID. +func (s *remoteStore) appendVendorProfileID( + profilesMap map[string]*store.EndDeviceProfile, + index VendorEndDevicesIndex, +) error { + for vendorProfileID, profileInfo := range index.ProfileIDs { + vendorProfileID, err := strconv.Atoi(vendorProfileID) + if err != nil { + return err + } + + if profileInfo.ProfileID != "" { + if _, ok := profilesMap[profileInfo.ProfileID]; !ok { + continue + } + + profilesMap[profileInfo.ProfileID].VendorProfileID = uint32(vendorProfileID) //nolint:gosec + } + + if profileInfo.EndDeviceID != "" { + profileKey := s.buildProfileKey( + profileInfo.EndDeviceID, + profileInfo.FirmwareVersion, + profileInfo.Region, + ) + if _, ok := profilesMap[profileKey]; !ok { + continue + } + profilesMap[profileKey].VendorProfileID = uint32(vendorProfileID) //nolint:gosec + } + } + + return nil +} + +func (*remoteStore) buildProfileKey(modelID, firmwareVersion, region string) string { + return fmt.Sprintf("%s-%s-%s", modelID, firmwareVersion, region) +} + // GetEndDeviceProfiles lists available LoRaWAN end device profiles per brand. // Note that this can be very slow, and does not support searching/sorting. // This function is primarily intended to be used for creating the bleve index. -func (s *remoteStore) GetEndDeviceProfiles(req store.GetEndDeviceProfilesRequest) (*store.GetEndDeviceProfilesResponse, error) { +func (s *remoteStore) GetEndDeviceProfiles( + req store.GetEndDeviceProfilesRequest, +) (*store.GetEndDeviceProfilesResponse, error) { if req.BrandID != "" { return s.getEndDeviceProfilesByBrand(req) } @@ -244,23 +305,64 @@ func (s *remoteStore) GetEndDeviceProfiles(req store.GetEndDeviceProfilesRequest return &store.GetEndDeviceProfilesResponse{ Count: end - start, Offset: start, - Total: uint32(len(all)), + Total: uint32(len(all)), //nolint:gosec Profiles: all[start:end], }, nil } var ( - errModelNotFound = errors.DefineNotFound("model_not_found", "model `{brand_id}/{model_id}` not found") - errBandNotFound = errors.DefineNotFound("band_not_found", "band `{band_id}` not found") - errNoProfileForBand = errors.DefineNotFound("no_profile_for_band", "device does not have a profile for band `{band_id}`") - errFirmwareVersionNotFound = errors.DefineNotFound("firmware_version_not_found", "firmware version `{firmware_version}` for model `{brand_id}/{model_id}` not found") + errModelNotFound = errors.DefineNotFound( + "model_not_found", + "model `{brand_id}/{model_id}` not found", + ) + errBandNotFound = errors.DefineNotFound( + "band_not_found", + "band `{band_id}` not found", + ) + errNoProfileForBand = errors.DefineNotFound( + "no_profile_for_band", + "device does not have a profile for band `{band_id}`", + ) + errFirmwareVersionNotFound = errors.DefineNotFound( + "firmware_version_not_found", + "firmware version `{firmware_version}` for model `{brand_id}/{model_id}` not found", + ) + errBrandWithVendorIDNotFound = errors.DefineNotFound( + "brand_with_vendor_id_not_found", + "brand with vendor ID `{vendor_id}` not found", + ) + errVendorProfileIDNotFound = errors.DefineNotFound( + "vendor_profile_id_not_found", + "vendor profile ID `{vendor_profile_id}` not found for vendor ID `{vendor_id}`", + ) + errNoTemplateIdentifiers = errors.DefineInvalidArgument( + "no_template_identifiers", + "one of version_ids or end_device_profile_ids must be set", + ) + errBandNotFoundForRegion = errors.DefineNotFound( + "band_not_found_for_region", + "band not found for region `{region}`", + ) + errMissingProfileIdentifiers = errors.DefineInvalidArgument( + "missing_profile_identifiers", + "both vendor ID and vendor profile ID must be provided", + ) ) // GetTemplate retrieves an end device template for an end device definition. -func (s *remoteStore) GetTemplate(req *ttnpb.GetTemplateRequest, profile *store.EndDeviceProfile) (*ttnpb.EndDeviceTemplate, error) { +func (s *remoteStore) GetTemplate( + req *ttnpb.GetTemplateRequest, +) (*ttnpb.EndDeviceTemplate, error) { ids := req.GetVersionIds() - if profile != nil { - return profile.ToTemplatePB(ids, nil) + if ids == nil { + if req.GetEndDeviceProfileIds() == nil { + return nil, errNoTemplateIdentifiers + } + versionIDs, err := s.getVersionIDsUsingProfileIDs(req.GetEndDeviceProfileIds()) + if err != nil { + return nil, err + } + ids = versionIDs } // Parse the models and return the End Device Profile that corresponds to the Band ID. @@ -288,9 +390,7 @@ func (s *remoteStore) GetTemplate(req *ttnpb.GetTemplateRequest, profile *store. } profileInfo, ok := ver.Profiles[ids.BandId] if !ok { - return nil, errNoProfileForBand.WithAttributes( - "band_id", ids.BandId, - ) + return nil, errNoProfileForBand.WithAttributes("band_id", ids.BandId) } profileVendorID := ids.BrandId @@ -315,7 +415,59 @@ func (s *remoteStore) GetTemplate(req *ttnpb.GetTemplateRequest, profile *store. ) } -var errNoCodec = errors.DefineNotFound("no_codec", "no codec defined for firmware version `{firmware_version}` and band `{band_id}`") +func (s *remoteStore) getVersionIDsUsingProfileIDs( + ids *ttnpb.GetTemplateRequest_EndDeviceProfileIdentifiers, +) (*ttnpb.EndDeviceVersionIdentifiers, error) { + if ids.VendorProfileId == 0 || ids.VendorId == 0 { + return nil, errMissingProfileIdentifiers.New() + } + + brandID, err := s.getBrandIDByVendorID(ids.VendorId) + if err != nil { + return nil, errBrandWithVendorIDNotFound.WithAttributes("vendor_id", ids.VendorId) + } + endDeviceProfilesIdentifiers, err := s.GetEndDeviceProfileIdentifiers( + store.GetEndDeviceProfileIdentifiersRequest{BrandID: brandID}, + ) + if err != nil { + return nil, err + } + + var profileIDs *store.EndDeviceProfileIdentifiers + for _, profileIdentifiers := range endDeviceProfilesIdentifiers.EndDeviceProfileIdentifiers { + vendorProfileID := strconv.Itoa(int(ids.VendorProfileId)) + if vendorProfileID == profileIdentifiers.VendorProfileID { + profileIDs = profileIdentifiers + break + } + } + if profileIDs == nil { + return nil, errVendorProfileIDNotFound.WithAttributes( + "vendor_id", ids.VendorId, + "vendor_profile_id", ids.VendorProfileId, + ) + } + + bandID, ok := regionToBandID[profileIDs.Region] + if !ok { + return nil, errBandNotFoundForRegion.WithAttributes("region", profileIDs.Region) + } + + versionIDs := &ttnpb.EndDeviceVersionIdentifiers{ + BrandId: brandID, + ModelId: profileIDs.EndDeviceID, + FirmwareVersion: profileIDs.FirmwareVersion, + HardwareVersion: profileIDs.HardwareVersion, + BandId: bandID, + } + + return versionIDs, nil +} + +var errNoCodec = errors.DefineNotFound( + "no_codec", + "no codec defined for firmware version `{firmware_version}` and band `{band_id}`", +) func (s *remoteStore) getCodecs(ids *ttnpb.EndDeviceVersionIdentifiers) (*EndDeviceCodecs, error) { models, err := s.GetModels(store.GetModelsRequest{ @@ -332,7 +484,7 @@ func (s *remoteStore) getCodecs(ids *ttnpb.EndDeviceVersionIdentifiers) (*EndDev return nil, errModelNotFound.WithAttributes("brand_id", ids.BrandId, "model_id", ids.ModelId) } model := models.Models[0] - var version *ttnpb.EndDeviceModel_FirmwareVersion = nil + var version *ttnpb.EndDeviceModel_FirmwareVersion for _, ver := range model.FirmwareVersions { if ver.Version == ids.FirmwareVersion { version = ver @@ -379,7 +531,10 @@ var ( errNoEncoder = errors.DefineNotFound("no_encoder", "no encoder defined for codec `{codec_id}`") ) -func (s *remoteStore) getDecoder(req store.GetCodecRequest, choose func(codecs *EndDeviceCodecs) *EndDeviceDecoderCodec) (*ttnpb.MessagePayloadDecoder, error) { +func (s *remoteStore) getDecoder( + req store.GetCodecRequest, + choose func(codecs *EndDeviceCodecs) *EndDeviceDecoderCodec, +) (*ttnpb.MessagePayloadDecoder, error) { codecs, err := s.getCodecs(req.GetVersionIds()) if err != nil { return nil, err @@ -448,7 +603,10 @@ func (s *remoteStore) GetDownlinkEncoder(req store.GetCodecRequest) (*ttnpb.Mess codec := codecs.DownlinkEncoder if codec.FileName == "" { - return nil, errNoEncoder.WithAttributes("firmware_version", req.GetVersionIds().FirmwareVersion, "band_id", req.GetVersionIds().BandId) + return nil, errNoEncoder.WithAttributes( + "firmware_version", req.GetVersionIds().FirmwareVersion, + "band_id", req.GetVersionIds().BandId, + ) } b, err := s.fetcher.File("vendor", req.GetVersionIds().BrandId, codec.FileName) @@ -489,7 +647,58 @@ func (s *remoteStore) GetDownlinkEncoder(req store.GetCodecRequest) (*ttnpb.Mess return pb, nil } +func (s *remoteStore) GetEndDeviceProfileIdentifiers( + req store.GetEndDeviceProfileIdentifiersRequest, +) (*store.GetEndDeviceProfileIdentifiersResponse, error) { + b, err := s.fetcher.File("vendor", req.BrandID, "index.yaml") + if err != nil { + return nil, errBrandNotFound.WithAttributes("brand_id", req.BrandID) + } + + index := VendorEndDevicesIndex{} + if err := yaml.Unmarshal(b, &index); err != nil { + return nil, err + } + + vendorProfiles := make([]*store.EndDeviceProfileIdentifiers, 0, len(index.ProfileIDs)) + for profileID, profile := range index.ProfileIDs { + // Skip profiles that don't specify the end device ID. + if profile.EndDeviceID == "" { + continue + } + + vendorProfiles = append(vendorProfiles, &store.EndDeviceProfileIdentifiers{ + VendorProfileID: profileID, + EndDeviceID: profile.EndDeviceID, + FirmwareVersion: profile.FirmwareVersion, + HardwareVersion: profile.HardwareVersion, + Region: profile.Region, + }) + } + + return &store.GetEndDeviceProfileIdentifiersResponse{ + EndDeviceProfileIdentifiers: vendorProfiles, + }, nil +} + +func (s *remoteStore) getBrandIDByVendorID(vendorID uint32) (string, error) { + brands, err := s.GetBrands(store.GetBrandsRequest{ + Paths: []string{"brand_id", "lora_alliance_vendor_id"}, + }) + if err != nil { + return "", err + } + + for _, brand := range brands.Brands { + if brand.LoraAllianceVendorId == vendorID { + return brand.BrandId, nil + } + } + + return "", errBrandNotFound.WithAttributes("vendor_id", vendorID) +} + // Close closes the store. -func (s *remoteStore) Close() error { +func (*remoteStore) Close() error { return nil } diff --git a/pkg/devicerepository/store/remote/remote_test.go b/pkg/devicerepository/store/remote/remote_test.go index 926e047aca..b31ece95c5 100644 --- a/pkg/devicerepository/store/remote/remote_test.go +++ b/pkg/devicerepository/store/remote/remote_test.go @@ -30,11 +30,15 @@ import ( ) func TestRemoteStore(t *testing.T) { + t.Parallel() a := assertions.New(t) s := remote.NewRemoteStore(fetch.FromFilesystem("testdata")) t.Run("TestGetBrands", func(t *testing.T) { + t.Parallel() + t.Run("Limit", func(t *testing.T) { + t.Parallel() list, err := s.GetBrands(store.GetBrandsRequest{ Paths: []string{ "brand_id", @@ -52,6 +56,7 @@ func TestRemoteStore(t *testing.T) { }) t.Run("SecondPage", func(t *testing.T) { + t.Parallel() list, err := s.GetBrands(store.GetBrandsRequest{ Paths: []string{ "brand_id", @@ -70,6 +75,7 @@ func TestRemoteStore(t *testing.T) { }) t.Run("Paths", func(t *testing.T) { + t.Parallel() list, err := s.GetBrands(store.GetBrandsRequest{ Paths: ttnpb.EndDeviceBrandFieldPathsNested, }) @@ -90,12 +96,19 @@ func TestRemoteStore(t *testing.T) { OrganizationUniqueIdentifiers: []string{"010203", "030405"}, Logo: "logo.svg", }, + { + BrandId: "windsensor-vendor", + Name: "Wind Sensor Vendor", + LoraAllianceVendorId: 43, + }, }) }) }) t.Run("TestGetModels", func(t *testing.T) { + t.Parallel() t.Run("AllBrands", func(t *testing.T) { + t.Parallel() list, err := s.GetModels(store.GetModelsRequest{ Paths: []string{ "brand_id", @@ -120,10 +133,16 @@ func TestRemoteStore(t *testing.T) { ModelId: "full-device", Name: "Full Device", }, + { + BrandId: "windsensor-vendor", + ModelId: "windsensor", + Name: "Wind Sensor", + }, }) }) t.Run("Limit", func(t *testing.T) { + t.Parallel() list, err := s.GetModels(store.GetModelsRequest{ BrandID: "foo-vendor", Limit: 1, @@ -144,6 +163,7 @@ func TestRemoteStore(t *testing.T) { }) t.Run("Offset", func(t *testing.T) { + t.Parallel() list, err := s.GetModels(store.GetModelsRequest{ BrandID: "foo-vendor", Limit: 1, @@ -165,6 +185,7 @@ func TestRemoteStore(t *testing.T) { }) t.Run("Paths", func(t *testing.T) { + t.Parallel() list, err := s.GetModels(store.GetModelsRequest{ BrandID: "foo-vendor", Paths: ttnpb.EndDeviceModelFieldPathsNested, @@ -232,6 +253,7 @@ func TestRemoteStore(t *testing.T) { }) t.Run("Full", func(t *testing.T) { + t.Parallel() a := assertions.New(t) list, err := s.GetModels(store.GetModelsRequest{ BrandID: "full-vendor", @@ -353,7 +375,9 @@ func TestRemoteStore(t *testing.T) { }) t.Run("TestGetTemplate", func(t *testing.T) { + t.Parallel() t.Run("ByEndDeviceVersionIdentifiers", func(t *testing.T) { + t.Parallel() template, err := s.GetTemplate(&ttnpb.GetTemplateRequest{ VersionIds: &ttnpb.EndDeviceVersionIdentifiers{ BrandId: "foo-vendor", @@ -361,7 +385,7 @@ func TestRemoteStore(t *testing.T) { FirmwareVersion: "1.0", BandId: "EU_863_870", }, - }, nil) + }) a.So(err, should.BeNil) a.So(template, should.Resemble, &ttnpb.EndDeviceTemplate{ EndDevice: &ttnpb.EndDevice{ @@ -391,32 +415,33 @@ func TestRemoteStore(t *testing.T) { ), }) }) - t.Run("ByProfile", func(t *testing.T) { + t.Parallel() + template, err := s.GetTemplate(&ttnpb.GetTemplateRequest{ - VersionIds: &ttnpb.EndDeviceVersionIdentifiers{ - BrandId: "foo-vendor", - }, EndDeviceProfileIds: &ttnpb.GetTemplateRequest_EndDeviceProfileIdentifiers{ - VendorId: 42, - VendorProfileId: 0, - }, - }, &store.EndDeviceProfile{ - VendorProfileID: 0, - RegionalParametersVersion: "RP001-1.0.3-RevA", - MACVersion: ttnpb.MACVersion_MAC_V1_0_3, - SupportsJoin: true, - Supports32BitFCnt: true, + VendorId: 43, + VendorProfileId: 1, + }, }) a.So(err, should.BeNil) a.So(template, should.Resemble, &ttnpb.EndDeviceTemplate{ EndDevice: &ttnpb.EndDevice{ VersionIds: &ttnpb.EndDeviceVersionIdentifiers{ - BrandId: "foo-vendor", + BrandId: "windsensor-vendor", + ModelId: "windsensor", + FirmwareVersion: "1.0", + HardwareVersion: "1.0", + BandId: "EU_863_870", + }, + Formatters: &ttnpb.MessagePayloadFormatters{ + UpFormatter: ttnpb.PayloadFormatter_FORMATTER_REPOSITORY, + DownFormatter: ttnpb.PayloadFormatter_FORMATTER_REPOSITORY, }, LorawanPhyVersion: ttnpb.PHYVersion_PHY_V1_0_3_REV_A, LorawanVersion: ttnpb.MACVersion_MAC_V1_0_3, SupportsJoin: true, + SupportsClassB: true, MacSettings: &ttnpb.MACSettings{ Supports_32BitFCnt: &ttnpb.BoolValue{ Value: true, @@ -430,6 +455,7 @@ func TestRemoteStore(t *testing.T) { "supports_class_c", "lorawan_version", "lorawan_phy_version", + "formatters", "mac_settings.supports_32_bit_f_cnt", ), }) @@ -437,7 +463,9 @@ func TestRemoteStore(t *testing.T) { }) t.Run("TestGetCodecs", func(t *testing.T) { + t.Parallel() t.Run("Missing", func(t *testing.T) { + t.Parallel() a := assertions.New(t) for _, ids := range []*ttnpb.EndDeviceVersionIdentifiers{ @@ -496,6 +524,7 @@ func TestRemoteStore(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { + t.Parallel() a := assertions.New(t) versionIDs := &ttnpb.EndDeviceVersionIdentifiers{ @@ -511,6 +540,7 @@ func TestRemoteStore(t *testing.T) { } t.Run("Examples", func(t *testing.T) { + t.Parallel() for _, tc := range []struct { name string f func(store.GetCodecRequest) (any, error) diff --git a/pkg/devicerepository/store/remote/schema.go b/pkg/devicerepository/store/remote/schema.go index aae1d0eea6..416b8d5fd9 100644 --- a/pkg/devicerepository/store/remote/schema.go +++ b/pkg/devicerepository/store/remote/schema.go @@ -17,6 +17,7 @@ package remote import ( "google.golang.org/protobuf/types/known/wrapperspb" + "go.thethings.network/lorawan-stack/v3/pkg/devicerepository/store" "go.thethings.network/lorawan-stack/v3/pkg/ttnpb" ) @@ -60,7 +61,8 @@ type VendorsIndex struct { // VendorEndDevicesIndex is the format of the `vendor//index.yaml` file. type VendorEndDevicesIndex struct { - EndDevices []string `yaml:"endDevices"` + EndDevices []string `yaml:"endDevices"` + ProfileIDs map[string]*store.EndDeviceProfileIdentifiers `yaml:"profileIDs,omitempty"` } // EndDeviceModel is the format of the `vendor//.yaml` file. diff --git a/pkg/devicerepository/store/remote/testdata/vendor/index.yaml b/pkg/devicerepository/store/remote/testdata/vendor/index.yaml index b392f124ba..31ddb34dae 100644 --- a/pkg/devicerepository/store/remote/testdata/vendor/index.yaml +++ b/pkg/devicerepository/store/remote/testdata/vendor/index.yaml @@ -14,3 +14,6 @@ vendors: name: Draft description: Vendor that should not be returned draft: true +- id: windsensor-vendor + name: Wind Sensor Vendor + vendorID: 43 diff --git a/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/index.yaml b/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/index.yaml new file mode 100644 index 0000000000..127e40b9e8 --- /dev/null +++ b/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/index.yaml @@ -0,0 +1,16 @@ +endDevices: +- windsensor + +profileIDs: + '1': + endDeviceID: 'windsensor' + firmwareVersion: '1.0' + hardwareVersion: '1.0' + region: 'EU863-870' + '2': + endDeviceID: 'windsensor' + firmwareVersion: '1.0' + hardwareVersion: '1.0' + region: 'US902-928' + '3': + id: 'windsor-profile' diff --git a/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/windsensor-profile.yaml b/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/windsensor-profile.yaml new file mode 100644 index 0000000000..e7a2d2c002 --- /dev/null +++ b/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/windsensor-profile.yaml @@ -0,0 +1,7 @@ +macVersion: '1.0.3' +regionalParametersVersion: 'RP001-1.0.3-RevA' +supportsJoin: true +maxEIRP: 16 +supports32bitFCnt: true +supportsClassB: true +supportsClassC: false diff --git a/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/windsensor.yaml b/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/windsensor.yaml new file mode 100644 index 0000000000..71cc8d3224 --- /dev/null +++ b/pkg/devicerepository/store/remote/testdata/vendor/windsensor-vendor/windsensor.yaml @@ -0,0 +1,192 @@ +name: Wind Sensor +description: Wind Sensor with controllable LED + +# Hardware versions (optional, use when you have revisions) +hardwareVersions: +- version: '1.0' + numeric: 1 +- version: '1.0-rev-A' + numeric: 2 + +# Firmware versions (at least one is mandatory) +firmwareVersions: +- # Firmware version + version: '1.0' + numeric: 1 + # Corresponding hardware versions (optional) + hardwareVersions: + - '1.0' + + # Firmware features (optional) + # Valid values are: remote rejoin (trigger a join from the application layer), transmission interval (configure how + # often he device sends a message). + features: + - remote rejoin + - transmission interval + + # LoRaWAN Device Profiles per region + # Supported regions are EU863-870, US902-928, AU915-928, AS923, CN779-787, EU433, CN470-510, KR920-923, IN865-867, + # RU864-870 + profiles: + EU863-870: + # Optional identifier of the vendor of the profile. When you specify the vendorID, the profile is loaded from + # the vendorID's folder. This allows you to reuse profiles from module or LoRaWAN end device stack vendors. + # If vendorID is empty, the current vendor ID is used. In this example, the vendorID is the current vendor ID, + # which is verbose. + vendorID: windsensor-vendor + # Identifier of the profile (lowercase, alphanumeric with dashes, max 36 characters) + id: windsensor-profile + lorawanCertified: true + codec: windsensor-codec + US902-928: + id: windsensor-profile + lorawanCertified: true + codec: windsensor-codec + +- # You can add more firmware versions and use different profiles per version + version: '2.0' + numeric: 2 + hardwareVersions: + - '1.0-rev-A' + profiles: + EU863-870: + id: windsensor-profile + lorawanCertified: true + codec: windsensor-codec + US902-928: + id: windsensor-profile + lorawanCertified: true + codec: windsensor-codec + AS923: + id: windsensor-profile + codec: windsensor-codec + +# Type of device (optional) +# Valid values are: devkit, module, cots +deviceType: cots + +# Sensors that this device features (optional) +# Valid values are: +# 4-20 ma, accelerometer, altitude, analog input, auxiliary, barometer, battery, button, bvoc, co, co2, conductivity, current, digital input, +# digital output, dissolved oxygen, distance, dust, energy, gps, gyroscope, h2s, hall effect, humidity, iaq, infrared, leaf wetness, level, +# light, lightning, link, magnetometer, moisture, motion, nfc, no, no2, o3, occupancy, optical meter, particulate matter, ph, pir, +# pm2.5, pm10, potentiometer, power, precipitation, pressure, proximity, pulse count, pulse frequency, radar, rainfall, reed switch, rssi, +# sap flow, smart valve, smoke, snr, so2, solar radiation, sound, strain, surface temperature, switch, temperature, tilt, time, turbidity, +# tvoc, uv, vapor pressure, velocity, vibration, voltage, water potential, water, weight, wifi ssid, wind direction, wind speed. +sensors: +- wind direction +- wind speed + +# Additional radios that this device has (optional) +# Valid values are: ble, nfc, wifi, cellular. +additionalRadios: +- ble +- cellular + +# Bridge interfaces (optional) +# Valid values are: modbus, m-bus, can bus, rs-485, sdi-12, analog, ethernet. +bridgeInterfaces: +- m-bus +- rs-485 + +# Dimensions in mm (optional) +# Use width, height, length and/or diameter +dimensions: + width: 34 + length: 26 + height: 77 + +# Weight in grams (optional) +weight: 350 + +# Battery information (optional) +battery: + replaceable: true + type: AA + +# Operating conditions (optional) +operatingConditions: + # Temperature (Celsius) + temperature: + min: -30 + max: 85 + # Relative humidity (fraction of 1) + relativeHumidity: + min: 0 + max: 0.97 + +# IP rating (optional) +ipCode: IP64 + +# Key provisioning (optional) +# Valid values are: custom (user can configure keys), join server and manifest. +keyProvisioning: +- custom +- join server + +# Key programming (optional) +# Valid values are: bluetooth, nfc, wifi, ethernet (via a webpage), serial (when the user has a serial interface to set the keys) +# and firmware (when the user should change the firmware to set the keys). +keyProgramming: +- serial +- firmware + +# Key security (optional) +# Valid values are: none, read protected and secure element. +keySecurity: none + +# Firmware programming (optional) +# Valid values are: serial (when the user has a serial interface to update the firmware), ethernet, fuota lorawan (when the device +# supports LoRaWAN FUOTA via standard interfaces) and fuota other (other wireless update mechanism). +firmwareProgramming: +- serial +- fuota lorawan + +# Product and data sheet URLs (optional) +productURL: https://example.org/wind-sensor +dataSheetURL: https://example.org/wind-sensor/datasheet.pdf +# Link to simple, easy onboarding instructions for the device (optional). +# Please do not use this for marketing or overly technical documents like a data sheet. +onboardingGuideURL: https://www.thethingsindustries.com/docs/devices/models/windsensor + +# Commercial information +resellerURLs: +- name: 'Reseller 1' + region: # valid regions are: Argentina, Australia, Brazil, Canada, China, European Union, India, Indonesia. + # Japan, Mexico, Russia, Saudi Arabia, South Africa, South Korea, Turkey, United States, Other + - European Union + url: https://example.org/reseller1 +- name: 'Reseller 2' + region: + - United States + - Canada + url: https://example.org/reseller2 +msrp: + EUR: 90 + USD: 120 + +# Photos +photos: + main: windsensor.png # Image needs to have a transparent background + other: + - windsensor-package.png # Image needs to have a transparent background + +# Youtube or Vimeo Video (optional) +videos: + main: https://www.youtube.com/watch?v=JHzxcD2oEn8 + +# Regulatory compliances (optional) +compliances: + safety: + - body: IEC + norm: EN + standard: 62368-1 + radioEquipment: + - body: ETSI + norm: EN + standard: 301 489-1 + version: 2.2.0 + - body: ETSI + norm: EN + standard: 301 489-3 + version: 2.1.0 diff --git a/pkg/webui/locales/ja.json b/pkg/webui/locales/ja.json index 9bea83f15d..e5f7719ae1 100644 --- a/pkg/webui/locales/ja.json +++ b/pkg/webui/locales/ja.json @@ -35,11 +35,11 @@ "components.file-input.index.noFileSelected": "選択されたファイルはありません", "components.file-input.index.fileProvided": "ファイルが提供されました", "components.file-input.index.tooBig": "選択したファイルが大きすぎます", - "components.form.field.tooltip.descriptionTitle": "これは何でしょう?", - "components.form.field.tooltip.locationTitle": "ここには何を入力すればよいのでしょうか?", - "components.form.field.tooltip.absenceTitle": "正しい値が見つからない場合はどうすればよいですか?", - "components.form.field.tooltip.viewGlossaryPage": "用語集を見る", - "components.form.field.tooltip.readMore": "続きを読む", + "components.form.field.tooltip.descriptionTitle": "", + "components.form.field.tooltip.locationTitle": "", + "components.form.field.tooltip.absenceTitle": "", + "components.form.field.tooltip.viewGlossaryPage": "", + "components.form.field.tooltip.readMore": "", "components.form.index.submitFailed": "投稿に失敗", "components.form.section.index.expand": "セクション展開", "components.form.section.index.collapse": "折りたたみ部分", @@ -65,8 +65,8 @@ "components.qr-modal-button.index.apply": "適用", "components.qr.input.capture.index.uploadImage": "写真をアップロード", "components.qr.input.capture.index.qrCodeNotFound": "QRコードが見つかりません", - "components.qr.input.video.index.fetchingCamera": "カメラを待つ…", - "components.qr.input.video.index.switchCamera": "カメラを切り替える", + "components.qr.input.video.index.fetchingCamera": "", + "components.qr.input.video.index.switchCamera": "", "components.qr.require-permission.permissionDeniedError": "パーミッションが拒否されました: カメラへのアクセスを許可するか、写真をアップロードしてください", "components.qr.require-permission.fetchingPermission": "カメラのアクセス許可を設定してください", "components.rights-group.index.selectAll": "全て選択", @@ -102,19 +102,19 @@ "console.components.application-general-settings-form.index.techContactDescription": "このアプリケーションの技術的な連絡先情報。通常、アプリケーションに関する技術/セキュリティの質問の連絡先を示すために使用されます。", "console.components.application-map-panel.index.deviceLocations": "", "console.components.default-routing-policy-form.index.doNotUseADefaultPolicy": "このネットワークでは、デフォルトのルーティングポリシーを使用しないでください", - "console.components.device-import-form.index.file": "ファイル", - "console.components.device-import-form.index.formatInfo": "フォーマット情報", - "console.components.device-import-form.index.selectAFile": "テンプレートファイルを選択してください", - "console.components.device-import-form.index.fileInfoPlaceholder": "テンプレート形式を選択してください", - "console.components.device-import-form.index.setClaimAuthCode": "クレーム認証コードの設定", - "console.components.device-import-form.index.targetedComponents": "対象となるコンポーネント", - "console.components.device-import-form.index.advancedSectionTitle": "エンドデバイスのクレームの詳細設定", - "console.components.device-import-form.index.infoText": "インポート機能を使用すると、登録情報を含むファイルをアップロードすることで、複数のエンドデバイスを一度に登録することができます。詳しくは、Importing End Devices のドキュメントもご覧ください", - "console.components.device-import-form.index.fallbackValuesImport": "インポートファイルが提供しない場合に備えて、フォールバック値を定義することができます。インポートされたファイルにフォールバック値として提供されていない、またはインポートされたファイルに提供されていない必須値を持つデバイスは、インポーターによってスキップされます", - "console.components.device-import-form.index.inputMethodDeviceRepo": "LoRaWANデバイスリポジトリからエンドデバイスプロファイルを読み込む", - "console.components.device-import-form.index.inputMethodManual": "LoRaWANのバージョンと周波数プランを手動で入力します", - "console.components.device-import-form.index.fallbackValues": "フォールバック値", - "console.components.device-import-form.index.noFallback": "フォールバック値は設定しない", + "console.components.device-import-form.index.file": "", + "console.components.device-import-form.index.formatInfo": "", + "console.components.device-import-form.index.selectAFile": "", + "console.components.device-import-form.index.fileInfoPlaceholder": "", + "console.components.device-import-form.index.setClaimAuthCode": "", + "console.components.device-import-form.index.targetedComponents": "", + "console.components.device-import-form.index.advancedSectionTitle": "", + "console.components.device-import-form.index.infoText": "", + "console.components.device-import-form.index.fallbackValuesImport": "", + "console.components.device-import-form.index.inputMethodDeviceRepo": "", + "console.components.device-import-form.index.inputMethodManual": "", + "console.components.device-import-form.index.fallbackValues": "", + "console.components.device-import-form.index.noFallback": "", "console.components.downlink-form.index.insertMode": "挿入モード", "console.components.downlink-form.index.payloadType": "ペイロード・タイプ", "console.components.downlink-form.index.bytes": "バイト", @@ -124,88 +124,88 @@ "console.components.downlink-form.index.bytesPayloadDescription": "ダウンリンクメッセージの希望ペイロードバイト数", "console.components.downlink-form.index.jsonPayloadDescription": "ダウンリンクメッセージのデコードされたペイロード", "console.components.downlink-form.index.invalidSessionWarning": "ダウンリンクは、有効なセッションを持つエンドデバイスに対してのみスケジュールすることができます。エンドデバイスがネットワークに正しく接続されていることを確認してください", - "console.components.events.messages.MACPayload": "MAC ペイロード", - "console.components.events.messages.devAddr": "DevAddr", - "console.components.events.messages.fPort": "FPort", - "console.components.events.messages.fCnt": "FCnt", - "console.components.events.messages.rawPayload": "Raw ペイロード", - "console.components.events.messages.txPower": "Tx Power", - "console.components.events.messages.dataRate": "データ転送速度", - "console.components.events.messages.bandwidth": "バンド幅", - "console.components.events.messages.metrics": "メトリックス", - "console.components.events.messages.versions": "バージョン", - "console.components.events.messages.snr": "SNR", - "console.components.events.messages.sessionKeyId": "セッションキーID", - "console.components.events.messages.selectedMacVersion": "選択されたMACバージョン", - "console.components.events.messages.rx1Delay": "Rx1 遅延", - "console.components.events.messages.rx1DataRateIndex": "Rx1 データレート・インデックス", - "console.components.events.messages.rx1Frequency": "Rx1 周波数", - "console.components.events.messages.rx2DataRateIndex": "Rx2 データレート・インデックス", - "console.components.events.messages.rx2Frequency": "Rx2 周波数", - "console.components.events.messages.class": "クラス", - "console.components.events.messages.eventDetails": "イベント詳細", - "console.components.events.messages.rawEvent": "Rawイベント", - "console.components.events.messages.errorOverviewEntry": "エラーが発生し、イベントを表示することができません。この行をクリックすると、生のイベントを見ることができます", - "console.components.events.messages.dataPreview": "データプレビュー", - "console.components.events.messages.dataFormats": "データフォーマット", - "console.components.events.messages.dataFormatsInformation": "イベントメッセージタイプの詳細については、{dataFormatsDocumentationLink}のドキュメントを参照してください", - "console.components.events.messages.seeAllActivity": "すべての活動閲覧", - "console.components.events.messages.syntheticEvent": "注意: このメタイベントはネットワークから発信されたものではなく、コンソールによって自動的に生成されたものです。これは、エンドデバイスやゲートウェイのアクティビティには関係ありません", - "console.components.events.messages.eventsTruncated": "古いイベントはメモリを節約するために切り捨てられています。ストリームごとの現在のイベント制限は{limit}です", - "console.components.events.messages.eventUnavailable": "このイベントはもう利用できません。メモリを節約するために切り捨てられたのでしょう", - "console.components.events.messages.verboseStream": "冗長ストリーム", - "console.components.events.messages.confirmedUplink": "アップリンク確認済み", + "console.components.events.messages.MACPayload": "", + "console.components.events.messages.devAddr": "", + "console.components.events.messages.fPort": "", + "console.components.events.messages.fCnt": "", + "console.components.events.messages.rawPayload": "", + "console.components.events.messages.txPower": "", + "console.components.events.messages.dataRate": "", + "console.components.events.messages.bandwidth": "", + "console.components.events.messages.metrics": "", + "console.components.events.messages.versions": "", + "console.components.events.messages.snr": "", + "console.components.events.messages.sessionKeyId": "", + "console.components.events.messages.selectedMacVersion": "", + "console.components.events.messages.rx1Delay": "", + "console.components.events.messages.rx1DataRateIndex": "", + "console.components.events.messages.rx1Frequency": "", + "console.components.events.messages.rx2DataRateIndex": "", + "console.components.events.messages.rx2Frequency": "", + "console.components.events.messages.class": "", + "console.components.events.messages.eventDetails": "", + "console.components.events.messages.rawEvent": "", + "console.components.events.messages.errorOverviewEntry": "", + "console.components.events.messages.dataPreview": "", + "console.components.events.messages.dataFormats": "", + "console.components.events.messages.dataFormatsInformation": "", + "console.components.events.messages.seeAllActivity": "", + "console.components.events.messages.syntheticEvent": "", + "console.components.events.messages.eventsTruncated": "", + "console.components.events.messages.eventUnavailable": "", + "console.components.events.messages.verboseStream": "", + "console.components.events.messages.confirmedUplink": "", "console.components.events.messages.goToLiveData": "", "console.components.events.messages.showingEventsFor": "", - "console.components.events.previews.shared.json-payload.index.invalid": "無効なJSON", + "console.components.events.previews.shared.json-payload.index.invalid": "", "console.components.gateway-api-keys-modal.index.modalTitle": "ダウンロードゲートウェイAPIキー", "console.components.gateway-api-keys-modal.index.buttonMessage": "キーをダウンロードしました", "console.components.gateway-api-keys-modal.index.description": "注意:このウィンドウを閉じると、これらのAPIキーはダウンロードできなくなります。必ずダウンロードして保存してください!", "console.components.gateway-api-keys-modal.index.downloadLns": "LNSキーをダウンロード", "console.components.gateway-api-keys-modal.index.downloadCups": "CUPSキーをダウンロード", "console.components.gateway-visibility-form.index.saveDefaultGatewayVisibility": "デフォルトゲートウェイの可視性を保存", - "console.components.location-form.index.deleteAllLocations": "すべての位置情報を削除", - "console.components.location-form.index.deleteFailure": "エラーが発生し、その場所を削除できませんでした", - "console.components.location-form.index.deleteLocation": "場所入力を削除", - "console.components.location-form.index.deleteSuccess": "場所は削除されました", - "console.components.location-form.index.deleteAllInfo": "下のチェックボックスを使用して、自動的に設定された位置データ(フレームペイロードやステータスメッセージなど)も削除できます。", - "console.components.location-form.index.deleteWarning": "本当に位置情報を削除しますか?このエンティティから、手動による位置情報の入力を削除します", - "console.components.location-form.index.deleteAllWarning": "本当に位置情報を削除しますか?このエンティティからすべての位置情報エントリーを削除します", - "console.components.location-form.index.loadingLocation": "場所の読み込み中...", - "console.components.location-form.index.mapDescription": "地図内をクリックして位置を設定", - "console.components.location-form.index.mapDescriptionDisabled": "自動設定されると、地図上に位置が表示されます", - "console.components.location-form.index.noLocationSetInfo": "現在、手動による位置情報の設定はありません", - "console.components.location-form.index.updateSuccess": "場所を更新しました", - "console.components.lorawan-version-input.index.phyVersionError": "地域パラメーターバージョンの取得に失敗しました", - "console.components.mac-settings-section.index.delayValue": "{count, plural, one {{count} 秒} other {{count} 秒}}", - "console.components.mac-settings-section.index.factoryPresetFreqDescription": "工場出荷時に設定されている周波数のリスト。注意:順序は尊重されます", - "console.components.mac-settings-section.index.advancedMacSettings": "MACの高度な設定", - "console.components.mac-settings-section.index.desiredPingSlotFrequencyTitle": "希望するpingスロット周波数", - "console.components.mac-settings-section.index.pingSlotPeriodicityDescription": "クラスBのpingスロットの周期性", - "console.components.mac-settings-section.index.pingSlotDataRateTitle": "Pingスロットのデータレートインデックス", - "console.components.mac-settings-section.index.desiredPingSlotDataRateTitle": "希望するpingスロットのデータレート", - "console.components.mac-settings-section.index.resetWarning": "リセットは安全ではなく、デバイスがリプレイ攻撃の影響を受けやすくなります", - "console.components.mac-settings-section.index.desiredRx1DataRateOffsetTitle": "希望するRx1データレートのオフセット値", - "console.components.mac-settings-section.index.desiredRx1DelayTitle": "希望するRx1遅延", - "console.components.mac-settings-section.index.rx2DataRateIndexTitle": "RX2データレートインデックス", - "console.components.mac-settings-section.index.desiredRx2DataRateIndexTitle": "希望するRx2データレート・インデックス", - "console.components.mac-settings-section.index.desiredRx2FrequencyTitle": "希望するRx2の周波数", - "console.components.mac-settings-section.index.updateSuccess": "MAC設定が更新されました", - "console.components.mac-settings-section.index.desiredBeaconFrequency": "希望するビーコン周波数", - "console.components.mac-settings-section.index.maxDutyCycle": "最大デューティーサイクル", - "console.components.mac-settings-section.index.desiredMaxDutyCycle": "希望する最大デューティサイクル", - "console.components.mac-settings-section.index.adrMargin": "ADRマージン", - "console.components.mac-settings-section.index.adrUplinks": "ADR送信回数", - "console.components.mac-settings-section.index.adrAdaptiveDataRate": "アダプティブデータレート(ADR)", - "console.components.mac-settings-section.index.adrDataRate": "ADR データレートインデックス", - "console.components.mac-settings-section.index.adrTransPower": "ADR送信電力インデックス", - "console.components.mac-settings-section.index.adrDynamic": "ダイナミックモード", - "console.components.mac-settings-section.index.adrStatic": "スタティックモード", - "console.components.mac-settings-section.index.desiredAdrAckLimit": "希望するADR ack limit", - "console.components.mac-settings-section.index.desiredAdrAckDelay": "希望するADR ack delay", - "console.components.mac-settings-section.index.adrAckValue": "{count, plural, one {every message} other {every {count} messages}}", - "console.components.mac-settings-section.index.statusCountPeriodicity": "ステータスカウントの周期性", - "console.components.mac-settings-section.index.statusTimePeriodicity": "ステータス時間の周期性", + "console.components.location-form.index.deleteAllLocations": "", + "console.components.location-form.index.deleteFailure": "", + "console.components.location-form.index.deleteLocation": "", + "console.components.location-form.index.deleteSuccess": "", + "console.components.location-form.index.deleteAllInfo": "", + "console.components.location-form.index.deleteWarning": "", + "console.components.location-form.index.deleteAllWarning": "", + "console.components.location-form.index.loadingLocation": "", + "console.components.location-form.index.mapDescription": "", + "console.components.location-form.index.mapDescriptionDisabled": "", + "console.components.location-form.index.noLocationSetInfo": "", + "console.components.location-form.index.updateSuccess": "", + "console.components.lorawan-version-input.index.phyVersionError": "", + "console.components.mac-settings-section.index.delayValue": "", + "console.components.mac-settings-section.index.factoryPresetFreqDescription": "", + "console.components.mac-settings-section.index.advancedMacSettings": "", + "console.components.mac-settings-section.index.desiredPingSlotFrequencyTitle": "", + "console.components.mac-settings-section.index.pingSlotPeriodicityDescription": "", + "console.components.mac-settings-section.index.pingSlotDataRateTitle": "", + "console.components.mac-settings-section.index.desiredPingSlotDataRateTitle": "", + "console.components.mac-settings-section.index.resetWarning": "", + "console.components.mac-settings-section.index.desiredRx1DataRateOffsetTitle": "", + "console.components.mac-settings-section.index.desiredRx1DelayTitle": "", + "console.components.mac-settings-section.index.rx2DataRateIndexTitle": "", + "console.components.mac-settings-section.index.desiredRx2DataRateIndexTitle": "", + "console.components.mac-settings-section.index.desiredRx2FrequencyTitle": "", + "console.components.mac-settings-section.index.updateSuccess": "", + "console.components.mac-settings-section.index.desiredBeaconFrequency": "", + "console.components.mac-settings-section.index.maxDutyCycle": "", + "console.components.mac-settings-section.index.desiredMaxDutyCycle": "", + "console.components.mac-settings-section.index.adrMargin": "", + "console.components.mac-settings-section.index.adrUplinks": "", + "console.components.mac-settings-section.index.adrAdaptiveDataRate": "", + "console.components.mac-settings-section.index.adrDataRate": "", + "console.components.mac-settings-section.index.adrTransPower": "", + "console.components.mac-settings-section.index.adrDynamic": "", + "console.components.mac-settings-section.index.adrStatic": "", + "console.components.mac-settings-section.index.desiredAdrAckLimit": "", + "console.components.mac-settings-section.index.desiredAdrAckDelay": "", + "console.components.mac-settings-section.index.adrAckValue": "", + "console.components.mac-settings-section.index.statusCountPeriodicity": "", + "console.components.mac-settings-section.index.statusTimePeriodicity": "", "console.components.mac-settings-section.index.dataRate": "", "console.components.mac-settings-section.index.dataRatePlaceholder": "", "console.components.mac-settings-section.index.minNbTrans": "", @@ -273,105 +273,105 @@ "console.components.oauth-client-form.messages.stateDescriptionDesc": "", "console.components.oauth-client-form.messages.adminContactDescription": "", "console.components.oauth-client-form.messages.techContactDescription": "", - "console.components.payload-formatters-form.index.repository": "デバイスリポジトリのフォーマッタを使用", - "console.components.payload-formatters-form.index.customJavascipt": "カスタムJavascriptフォーマッター", - "console.components.payload-formatters-form.index.formatterType": "フォーマッタータイプ", - "console.components.payload-formatters-form.index.formatterCode": "フォーマッターコード", - "console.components.payload-formatters-form.index.formatterCodeReadOnly": "フォーマッターコード(読み取り専用)", - "console.components.payload-formatters-form.index.grpcHost": "GRPCホスト", - "console.components.payload-formatters-form.index.grpcFieldDescription": "接続先サービスのアドレス", - "console.components.payload-formatters-form.index.appFormatter": "アプリケーションペイロードフォーマッタを使用", - "console.components.payload-formatters-form.index.appFormatterWarning": "このオプションは、アップリンクとダウンリンクの両方のフォーマッタをアプリケーションリンクのデフォルトに設定します", - "console.components.payload-formatters-form.index.defaultFormatter": "ここ をクリックすると、このアプリケーションのデフォルトのペイロードフォーマッタを変更することができます。このアプリケーションのペイロードフォーマッタは現在 `{defaultFormatter}` に設定されています", - "console.components.payload-formatters-form.index.pasteRepositoryFormatter": "リポジトリフォーマッター貼り付け", - "console.components.payload-formatters-form.index.pasteApplicationFormatter": "アプリケーションフォーマッター貼り付け", - "console.components.payload-formatters-form.index.learnMoreAboutDeviceRepo": "デバイスリポジトリ―フォーマッターオプションとは何ですか?", - "console.components.payload-formatters-form.index.learnMoreAboutPayloadFormatters": "ペイロードフォーマッターの詳細はこちら", - "console.components.payload-formatters-form.index.learnMoreAboutCayenne": "CayenneLPPとは何ですか?", - "console.components.payload-formatters-form.index.noRepositoryWarning": "アプリケーションのフォーマッタは`リポジトリ`に設定されていますが、このデバイスはLoRaWANデバイスリポジトリに関連するフォーマッタを持ちません。そのため、このエンドデバイスのメッセージはフォーマットされません", - "console.components.payload-formatters-form.test-form.index.validResult": "ペイロードは有効です", - "console.components.payload-formatters-form.test-form.index.noResult": "スト結果はまだ生成されていません", - "console.components.payload-formatters-form.test-form.index.testDecoder": "デコーダーのテスト", - "console.components.payload-formatters-form.test-form.index.testEncoder": "エンコーダーのテスト", - "console.components.payload-formatters-form.test-form.index.testSubTitle": "テスト", - "console.components.payload-formatters-form.test-form.index.testFatalError": "フォーマッターコードの解釈時にエラーが発生しました", - "console.components.payload-formatters-form.test-form.index.testError": "テスト結果にユーザー定義のエラーが含まれています", - "console.components.payload-formatters-form.test-form.index.testWarning": "テスト結果にユーザー定義の警告が表示されます", - "console.components.payload-formatters-form.test-form.index.bytePayload": "バイトペイロード", - "console.components.payload-formatters-form.test-form.index.jsonPayload": "JSONペイロード", - "console.components.payload-formatters-form.test-form.index.emptyPayload": "返されたペイロードは空でした", - "console.components.payload-formatters-form.test-form.index.decodedPayload": "デコードされたテストペイロード", - "console.components.payload-formatters-form.test-form.index.completeUplink": "アップリンクデータを完成", - "console.components.payload-formatters-form.test-form.index.testResult": "テスト結果", - "console.components.payload-formatters-form.test-form.index.errorInformation": "エラー情報", - "console.components.pubsub-form.messages.idPlaceholder": "my-new-pubsub", - "console.components.pubsub-form.messages.messageInfo": "有効なメッセージタイプごとに、オプションのサブトピックを定義することができます", - "console.components.pubsub-form.messages.deletePubsub": "Pub/Subの削除", - "console.components.pubsub-form.messages.modalWarning": "Pub/Sub \"{pubsubId}\" を削除してもよろしいですか?Pub/Subの削除は元に戻すことができません", - "console.components.pubsub-form.messages.headers": "ヘッダー", - "console.components.pubsub-form.messages.headersValidateRequired": "すべてのヘッダーのエントリ値が必須です。空のエントリは削除してください", - "console.components.pubsub-form.messages.usernamePlaceholder": "my-username", - "console.components.pubsub-form.messages.passwordPlaceholder": "my-username", - "console.components.pubsub-form.messages.natsAddressPlaceholder": "nats.example.com", - "console.components.pubsub-form.messages.natsPortPlaceholder": "4222", - "console.components.pubsub-form.messages.natsConfig": "NATS 構成", - "console.components.pubsub-form.messages.mqttConfig": "MQTT 構成", - "console.components.pubsub-form.messages.mqttClientIdPlaceholder": "my-client-id", - "console.components.pubsub-form.messages.mqttServerUrlPlaceholder": "mqtts://example.com", - "console.components.pubsub-form.messages.subscribeQos": "QoSを購読", - "console.components.pubsub-form.messages.providerDescription": "Pub/Subプロバイダーの変更が管理者により無効化", - "console.components.pubsub-form.messages.publishQos": "QoSを発行", - "console.components.pubsub-form.messages.tlsCa": "ルート認証局証明書", - "console.components.pubsub-form.messages.tlsClientCert": "クライアント証明書", - "console.components.pubsub-form.messages.tlsClientKey": "クライアント秘密鍵", - "console.components.pubsub-form.messages.selectPemFile": ".pemファイルを選択してください…", - "console.components.pubsub-form.messages.pemFileProvided": ".pemファイルが提供されました", - "console.components.pubsub-form.messages.useCredentials": "証明書を使用", - "console.components.pubsub-form.messages.alreadyExistsModalMessage": "ID \"{id}\" を持つ Pub/Sub が既に存在します。このPub/Subを置き換えしますか?", - "console.components.pubsub-form.messages.replacePubsub": "Pub/Subを置き換え", - "console.components.pubsub-form.messages.useSecureConnection": "安全な接続を使用", - "console.components.pubsub-form.messages.pubsubsDescription": "Pub/Sub統合により、The Things Stack内蔵のMQTTクライアントまたはNATSクライアントを使用して、アプリケーションサーバーがトピックを公開および購読することができます。詳しくは、<リンク>Pub/Subガイドをご覧ください", - "console.components.routing-policy-form.index.saveDefaultPolicy": "デフォルトポリシーの保存", - "console.components.routing-policy-form.index.useSpecificPolicy": "ネットワーク固有のルーティングポリシーを使用", - "console.components.routing-policy-form.index.doNotUseAPolicy": "このネットワークには、ルーティングポリシーを使用しないでください", - "console.components.uplink-form.index.payloadDescription": "アップリンクメッセージの希望するペイロードバイト数", - "console.components.uplink-form.index.uplinkSuccess": "アップリンク送信済", - "console.components.webhook-form.index.idPlaceholder": "my-new-webhook", - "console.components.webhook-form.index.messageInfo": "有効なメッセージタイプごとに、オプションのパスをベースURLに合わせて定義することができます", - "console.components.webhook-form.index.deleteWebhook": "Webhookの削除", - "console.components.webhook-form.index.modalWarning": "webhook \"{webhookId}\"を削除してもよろしいですか?webhookの削除は元に戻すことができません", - "console.components.webhook-form.index.additionalHeaders": "追加ヘッダー", - "console.components.webhook-form.index.downlinkAPIKey": "ダウンリンクAPIキー", - "console.components.webhook-form.index.downlinkAPIKeyDesc": "API キーは、\"X-Downlink-APIikey\" ヘッダーを使用してエンドポイントに提供されます", - "console.components.webhook-form.index.templateInformation": "テンプレート情報", - "console.components.webhook-form.index.updateErrorTitle": "Webhookを更新できませんでした", - "console.components.webhook-form.index.createErrorTitle": "Webhookを作成できませんでした", - "console.components.webhook-form.index.reactivateButtonMessage": "リアクティベート", - "console.components.webhook-form.index.suspendedWebhookMessage": "このWebhookは、転送に何度か失敗したため、非アクティブ化されました。 {webhookRetryInterval}の後に自動的に再アクティブ化されます。すぐに再アクティブ化したい場合は、以下のボタンを使用してください", - "console.components.webhook-form.index.pendingInfo": "この Webhook は、最初の正規のリクエストを試みるまで、現在保留中です。リクエストの失敗が多すぎる場合、Webhookは制限されることがあることに注意してください", - "console.components.webhook-form.index.messagePathValidateTooLong": "有効なメッセージパスは最大64文字です", - "console.components.webhook-form.index.basicAuthCheckbox": "基本アクセス認証(basic auth)を使用", - "console.components.webhook-form.index.requestBasicAuth": "リクエスト認証", - "console.components.webhook-form.index.validateNoColon": "ベーシック認証のユーザー名にはコロンを含めることはできません", - "console.components.webhook-form.index.validateEmpty": "空のヘッダーエントリーがないこと。そのようなエントリは、投稿前に削除してください", - "console.components.webhook-form.index.validateNoDuplicate": "ヘッダーは重複してはいけません。同じキーのヘッダーは削除または統合してください", - "console.components.webhook-form.index.webhooksDescription": "Webhooks機能により、The Things Stackは特定のHTTP(S)エンドポイントにアプリケーション関連のメッセージを送信することができます。また、Webhookを使用して、エンドデバイスへのダウンリンクをスケジュールすることができます。詳しくは<リンク>Webhooksガイドでご確認ください", - "console.components.webhook-form.index.filterEventData": "イベントデータの絞り込み", - "console.components.webhook-form.index.fieldMaskPlaceholder": "フィルターパスの選択", - "console.components.webhook-form.index.filtersAdd": "フィルターパスの追加", - "console.components.webhook-template-form.index.createTemplate": "{template} Webhook作成", - "console.components.webhook-template-form.index.idPlaceholder": "my-new-{templateId}-webhook", - "console.components.webhook-template-info.index.about": "{name}について", - "console.components.webhook-template-info.index.setupWebhook": "{name} のWebhookを設定する", - "console.components.webhook-template-info.index.editWebhook": "{name} のWebhookを編集", + "console.components.payload-formatters-form.index.repository": "", + "console.components.payload-formatters-form.index.customJavascipt": "", + "console.components.payload-formatters-form.index.formatterType": "", + "console.components.payload-formatters-form.index.formatterCode": "", + "console.components.payload-formatters-form.index.formatterCodeReadOnly": "", + "console.components.payload-formatters-form.index.grpcHost": "", + "console.components.payload-formatters-form.index.grpcFieldDescription": "", + "console.components.payload-formatters-form.index.appFormatter": "", + "console.components.payload-formatters-form.index.appFormatterWarning": "", + "console.components.payload-formatters-form.index.defaultFormatter": "", + "console.components.payload-formatters-form.index.pasteRepositoryFormatter": "", + "console.components.payload-formatters-form.index.pasteApplicationFormatter": "", + "console.components.payload-formatters-form.index.learnMoreAboutDeviceRepo": "", + "console.components.payload-formatters-form.index.learnMoreAboutPayloadFormatters": "", + "console.components.payload-formatters-form.index.learnMoreAboutCayenne": "", + "console.components.payload-formatters-form.index.noRepositoryWarning": "", + "console.components.payload-formatters-form.test-form.index.validResult": "", + "console.components.payload-formatters-form.test-form.index.noResult": "", + "console.components.payload-formatters-form.test-form.index.testDecoder": "", + "console.components.payload-formatters-form.test-form.index.testEncoder": "", + "console.components.payload-formatters-form.test-form.index.testSubTitle": "", + "console.components.payload-formatters-form.test-form.index.testFatalError": "", + "console.components.payload-formatters-form.test-form.index.testError": "", + "console.components.payload-formatters-form.test-form.index.testWarning": "", + "console.components.payload-formatters-form.test-form.index.bytePayload": "", + "console.components.payload-formatters-form.test-form.index.jsonPayload": "", + "console.components.payload-formatters-form.test-form.index.emptyPayload": "", + "console.components.payload-formatters-form.test-form.index.decodedPayload": "", + "console.components.payload-formatters-form.test-form.index.completeUplink": "", + "console.components.payload-formatters-form.test-form.index.testResult": "", + "console.components.payload-formatters-form.test-form.index.errorInformation": "", + "console.components.pubsub-form.messages.idPlaceholder": "", + "console.components.pubsub-form.messages.messageInfo": "", + "console.components.pubsub-form.messages.deletePubsub": "", + "console.components.pubsub-form.messages.modalWarning": "", + "console.components.pubsub-form.messages.headers": "", + "console.components.pubsub-form.messages.headersValidateRequired": "", + "console.components.pubsub-form.messages.usernamePlaceholder": "", + "console.components.pubsub-form.messages.passwordPlaceholder": "", + "console.components.pubsub-form.messages.natsAddressPlaceholder": "", + "console.components.pubsub-form.messages.natsPortPlaceholder": "", + "console.components.pubsub-form.messages.natsConfig": "", + "console.components.pubsub-form.messages.mqttConfig": "", + "console.components.pubsub-form.messages.mqttClientIdPlaceholder": "", + "console.components.pubsub-form.messages.mqttServerUrlPlaceholder": "", + "console.components.pubsub-form.messages.subscribeQos": "", + "console.components.pubsub-form.messages.providerDescription": "", + "console.components.pubsub-form.messages.publishQos": "", + "console.components.pubsub-form.messages.tlsCa": "", + "console.components.pubsub-form.messages.tlsClientCert": "", + "console.components.pubsub-form.messages.tlsClientKey": "", + "console.components.pubsub-form.messages.selectPemFile": "", + "console.components.pubsub-form.messages.pemFileProvided": "", + "console.components.pubsub-form.messages.useCredentials": "", + "console.components.pubsub-form.messages.alreadyExistsModalMessage": "", + "console.components.pubsub-form.messages.replacePubsub": "", + "console.components.pubsub-form.messages.useSecureConnection": "", + "console.components.pubsub-form.messages.pubsubsDescription": "", + "console.components.routing-policy-form.index.saveDefaultPolicy": "", + "console.components.routing-policy-form.index.useSpecificPolicy": "", + "console.components.routing-policy-form.index.doNotUseAPolicy": "", + "console.components.uplink-form.index.payloadDescription": "", + "console.components.uplink-form.index.uplinkSuccess": "", + "console.components.webhook-form.index.idPlaceholder": "", + "console.components.webhook-form.index.messageInfo": "", + "console.components.webhook-form.index.deleteWebhook": "", + "console.components.webhook-form.index.modalWarning": "", + "console.components.webhook-form.index.additionalHeaders": "", + "console.components.webhook-form.index.downlinkAPIKey": "", + "console.components.webhook-form.index.downlinkAPIKeyDesc": "", + "console.components.webhook-form.index.templateInformation": "", + "console.components.webhook-form.index.updateErrorTitle": "", + "console.components.webhook-form.index.createErrorTitle": "", + "console.components.webhook-form.index.reactivateButtonMessage": "", + "console.components.webhook-form.index.suspendedWebhookMessage": "", + "console.components.webhook-form.index.pendingInfo": "", + "console.components.webhook-form.index.messagePathValidateTooLong": "", + "console.components.webhook-form.index.basicAuthCheckbox": "", + "console.components.webhook-form.index.requestBasicAuth": "", + "console.components.webhook-form.index.validateNoColon": "", + "console.components.webhook-form.index.validateEmpty": "", + "console.components.webhook-form.index.validateNoDuplicate": "", + "console.components.webhook-form.index.webhooksDescription": "", + "console.components.webhook-form.index.filterEventData": "", + "console.components.webhook-form.index.fieldMaskPlaceholder": "", + "console.components.webhook-form.index.filtersAdd": "", + "console.components.webhook-template-form.index.createTemplate": "", + "console.components.webhook-template-form.index.idPlaceholder": "", + "console.components.webhook-template-info.index.about": "", + "console.components.webhook-template-info.index.setupWebhook": "", + "console.components.webhook-template-info.index.editWebhook": "", "console.containers.access-point-list.index.lastRefresh": "", "console.containers.access-point-list.index.description": "", "console.containers.access-point-list.index.scanningWifi": "", - "console.containers.api-key-form.edit.deleteKey": "削除キー", - "console.containers.api-key-form.edit.modalWarning": "APIキー{keyName}を削除してもよろしいですか?APIキーの削除は元に戻すことができません", - "console.containers.api-key-form.edit.updateSuccess": "APIキーの更新", - "console.containers.api-key-form.edit.deleteSuccess": "APIキーの削除", - "console.containers.api-keys-table.index.grantedRights": "許諾された権利", + "console.containers.api-key-form.edit.deleteKey": "", + "console.containers.api-key-form.edit.modalWarning": "", + "console.containers.api-key-form.edit.updateSuccess": "", + "console.containers.api-key-form.edit.deleteSuccess": "", + "console.containers.api-keys-table.index.grantedRights": "", "console.containers.app-status-badge.index.upcomingMaintenance": "", "console.containers.app-status-badge.index.degradedPerformance": "", "console.containers.app-status-badge.index.maintenanceInProgress": "", @@ -383,34 +383,34 @@ "console.containers.app-status-badge.index.maintenance": "", "console.containers.app-status-badge.index.maintenanceScheduledSubtitle": "", "console.containers.application-events.index.applicationEventsOf": "", - "console.containers.application-general-settings.index.updateSuccess": "アプリケーションを更新", + "console.containers.application-general-settings.index.updateSuccess": "", "console.containers.application-overview-header.index.addBookmarkFail": "", "console.containers.application-overview-header.index.removeBookmarkFail": "", "console.containers.application-overview-header.index.lastSeenAvailableTooltip": "", "console.containers.application-overview-header.index.noActivityTooltip": "", "console.containers.application-overview-header.index.deviceCount": "", - "console.containers.application-payload-formatters.downlink.title": "デフォルトのダウンリンクペイロードフォーマッター", - "console.containers.application-payload-formatters.downlink.infoText": "個々のエンドデバイスの「Payload formatter」タブを使用して、ダウンリンクのペイロードフォーマッタをテストし、エンドデバイスごとに個別のペイロードフォーマッタ設定を定義することができます", - "console.containers.application-payload-formatters.downlink.downlinkResetWarning": "現在のダウンリンクペイロードフォーマッターを表示するのに十分な権限がありません。上書きのみ許可されています", - "console.containers.application-payload-formatters.uplink.title": "デフォルトのアップリンクペイロードフォーマッター", - "console.containers.application-payload-formatters.uplink.infoText": "これらのペイロードフォーマッタは、このアプリケーション内のすべてのエンドデバイスからのアップリンクメッセージで実行されます。注意:エンドデバイスレベルのペイロードフォーマッタが優先されます", - "console.containers.application-payload-formatters.uplink.uplinkResetWarning": "個々のエンドデバイスの「Payload formatter」タブを使用して、アップリンクのペイロードフォーマッタをテストし、エンドデバイスごとに個別のペイロードフォーマッタ設定を定義することができます", - "console.containers.applications-form.index.applicationName": "アプリケーション名", - "console.containers.applications-form.index.appIdPlaceholder": "my-new-application", - "console.containers.applications-form.index.appNamePlaceholder": "私の新しいアプリケーション", - "console.containers.applications-form.index.appDescPlaceholder": "私の新しいアプリケーションの説明", - "console.containers.applications-form.index.appDescDescription": "アプリケーションの説明(任意)。アプリケーションに関するメモを保存するためにも使用できます", - "console.containers.applications-form.index.appDescription": "アプリケーション内では、エンドデバイスの登録と管理、センサーデータの収集、および多くの統合オプションを使用してそれに対応することができます。<リンク>アプリケーションガイドで詳細をご覧ください", - "console.containers.applications-table.index.restoreSuccess": "アプリケーションの復元", - "console.containers.applications-table.index.restoreFail": "エラーが発生し、アプリケーションを復元することができませんでした", - "console.containers.applications-table.index.purgeSuccess": "アプリケーションパージ済み", - "console.containers.applications-table.index.purgeFail": "エラーが発生したため、アプリケーションをパージすることができませんでした", - "console.containers.applications-table.index.otherClusterTooltip": "このアプリケーションは、別のクラスタ(`{host}`)に登録されています。このアプリケーションにアクセスするには、このアプリケーションが登録されているクラスタのコンソールを使用します", - "console.containers.deployment-component-status.index.availableComponents": "利用可能なコンポーネント", - "console.containers.deployment-component-status.index.versionInfo": "デプロイメント", - "console.containers.deployment-component-status.index.statusPage": "ステータスページに移動します", - "console.containers.deployment-component-status.index.seeChangelog": "変更履歴を見る", - "console.containers.dev-addr-input.index.devAddrFetchingFailure": "エラーが発生し、エンドデバイスのアドレスを生成できませんでした", + "console.containers.application-payload-formatters.downlink.title": "", + "console.containers.application-payload-formatters.downlink.infoText": "", + "console.containers.application-payload-formatters.downlink.downlinkResetWarning": "", + "console.containers.application-payload-formatters.uplink.title": "", + "console.containers.application-payload-formatters.uplink.infoText": "", + "console.containers.application-payload-formatters.uplink.uplinkResetWarning": "", + "console.containers.applications-form.index.applicationName": "", + "console.containers.applications-form.index.appIdPlaceholder": "", + "console.containers.applications-form.index.appNamePlaceholder": "", + "console.containers.applications-form.index.appDescPlaceholder": "", + "console.containers.applications-form.index.appDescDescription": "", + "console.containers.applications-form.index.appDescription": "", + "console.containers.applications-table.index.restoreSuccess": "", + "console.containers.applications-table.index.restoreFail": "", + "console.containers.applications-table.index.purgeSuccess": "", + "console.containers.applications-table.index.purgeFail": "", + "console.containers.applications-table.index.otherClusterTooltip": "", + "console.containers.deployment-component-status.index.availableComponents": "", + "console.containers.deployment-component-status.index.versionInfo": "", + "console.containers.deployment-component-status.index.statusPage": "", + "console.containers.deployment-component-status.index.seeChangelog": "", + "console.containers.dev-addr-input.index.devAddrFetchingFailure": "", "console.containers.dev-eui-component.index.unknownError": "", "console.containers.device-events.index.deviceEventsOf": "", "console.containers.device-general-information-panel.index.activationInfo": "", @@ -418,77 +418,77 @@ "console.containers.device-general-information-panel.index.pendingSessionInfo": "", "console.containers.device-general-information-panel.index.sessionStartedAt": "", "console.containers.device-general-information-panel.index.noSession": "", - "console.containers.device-importer.messages.proceed": "エンドデバイスリストへ進む", - "console.containers.device-importer.messages.retry": "ゼロからやり直す", - "console.containers.device-importer.messages.abort": "中止する", - "console.containers.device-importer.messages.converting": "テンプレートの変換...", - "console.containers.device-importer.messages.creating": "エンドデバイスの作成...", - "console.containers.device-importer.messages.operationInProgress": "作業中", - "console.containers.device-importer.messages.operationHalted": "作業停止", - "console.containers.device-importer.messages.operationFinished": "操作終了", - "console.containers.device-importer.messages.operationAborted": "操作中止", - "console.containers.device-importer.messages.errorTitle": "エラーが発生し、操作を完了することができませんでした", - "console.containers.device-importer.messages.conversionErrorTitle": "デバイスをインポートできませんでした", - "console.containers.device-importer.messages.conversionErrorMessage": "提供されたエンドデバイステンプレートの処理中にエラーが発生しました。これは、無効なフォーマット、シンタックス、またはファイルエンコーディングが原因である可能性があります。提供されたテンプレートファイルを確認し、もう一度やり直してください。詳しくは、エンドデバイスのインポートのドキュメントもご覧ください", - "console.containers.device-importer.messages.incompleteWarningTitle": "すべてのデバイスが正常にインポートされたわけではありません", - "console.containers.device-importer.messages.incompleteWarningMessage": "{count, number} {count, plural, one {エンドデバイス} other {エンドデバイス}}は、登録試行がエラーにより終了したため、正常にインポートできませんでした。", - "console.containers.device-importer.messages.incompleteStatus": "以下の{count, plural, one {end device} other {end devices}}の登録に失敗しました:", - "console.containers.device-importer.messages.noneWarningTitle": "エンドデバイスが作成されてません", - "console.containers.device-importer.messages.noneWarningMessage": "登録しようとするとエラーが発生するため、指定したエンドデバイスは1つもインポートされませんでした", - "console.containers.device-importer.messages.processLog": "プロセスログ", - "console.containers.device-importer.messages.progress": "{deviceCount, number}のうち{errorCount, number} {deviceCount, plural, one {エンドデバイス} other {エンドデバイス}}を正常に変換しました", - "console.containers.device-importer.messages.successInfoTitle": "全てのエンドデバイスのインポートに成功", - "console.containers.device-importer.messages.successInfoMessage": "指定されたエンドデバイスはすべて正常に変換され、インポートされました", - "console.containers.device-importer.messages.documentationHint": "より詳細な情報と解決策については、エンドデバイスをインポート のドキュメントもご覧ください", - "console.containers.device-importer.messages.abortWarningTitle": "デバイスのインポートを中止", - "console.containers.device-importer.messages.abortWarningMessage": "エンドデバイスのインポートが中止され、残りの {count, number} {count, plural, one {エンドデバイス} other {エンドデバイス}} はインポートされていません", - "console.containers.device-importer.messages.largeFileWarningMessage": "{warningThreshold}を超えるサイズのファイルを提供すると、インポート処理中に問題が発生することがあります。そのようなファイルは、複数の小さなファイルに分割して、1つずつインポートすることをお勧めします", + "console.containers.device-importer.messages.proceed": "", + "console.containers.device-importer.messages.retry": "", + "console.containers.device-importer.messages.abort": "", + "console.containers.device-importer.messages.converting": "", + "console.containers.device-importer.messages.creating": "", + "console.containers.device-importer.messages.operationInProgress": "", + "console.containers.device-importer.messages.operationHalted": "", + "console.containers.device-importer.messages.operationFinished": "", + "console.containers.device-importer.messages.operationAborted": "", + "console.containers.device-importer.messages.errorTitle": "", + "console.containers.device-importer.messages.conversionErrorTitle": "", + "console.containers.device-importer.messages.conversionErrorMessage": "", + "console.containers.device-importer.messages.incompleteWarningTitle": "", + "console.containers.device-importer.messages.incompleteWarningMessage": "", + "console.containers.device-importer.messages.incompleteStatus": "", + "console.containers.device-importer.messages.noneWarningTitle": "", + "console.containers.device-importer.messages.noneWarningMessage": "", + "console.containers.device-importer.messages.processLog": "", + "console.containers.device-importer.messages.progress": "", + "console.containers.device-importer.messages.successInfoTitle": "", + "console.containers.device-importer.messages.successInfoMessage": "", + "console.containers.device-importer.messages.documentationHint": "", + "console.containers.device-importer.messages.abortWarningTitle": "", + "console.containers.device-importer.messages.abortWarningMessage": "", + "console.containers.device-importer.messages.largeFileWarningMessage": "", "console.containers.device-info-panel.index.endDeviceInfo": "", "console.containers.device-info-panel.index.deviceRepository": "", "console.containers.device-info-panel.index.deviceWebsite": "", "console.containers.device-info-panel.index.rssi": "", "console.containers.device-info-panel.index.snr": "", "console.containers.device-info-panel.index.notInDeviceRepository": "", - "console.containers.device-onboarding-form.messages.endDeviceType": "エンドデバイスの種類", - "console.containers.device-onboarding-form.messages.provisioningTitle": "提供する情報", - "console.containers.device-onboarding-form.messages.inputMethod": "入力方法", - "console.containers.device-onboarding-form.messages.inputMethodDeviceRepo": "LoRaWAN Device Repositoryでエンドデバイスを選択します", - "console.containers.device-onboarding-form.messages.inputMethodManual": "エンドデバイスの仕様を手動で入力", - "console.containers.device-onboarding-form.messages.continueManual": "続けて、バージョンと周波数プランの情報を入力してください", - "console.containers.device-onboarding-form.messages.continueJoinEui": "オンボーディングオプションを決定するために、エンドデバイスのJoinEUIを入力してください", - "console.containers.device-onboarding-form.messages.changeDeviceType": "本当に入力方法を変更するのですか?現在のフォームの進行状況は失われます", - "console.containers.device-onboarding-form.messages.changeDeviceTypeButton": "入力方法の変更", - "console.containers.device-onboarding-form.messages.confirmedRegistration": "このエンドデバイスは、ネットワークに登録することができます", - "console.containers.device-onboarding-form.messages.confirmedClaiming": "このエンドデバイスはクレームが可能です", - "console.containers.device-onboarding-form.messages.cannotConfirmEui": "エラーが発生し、JoinEUIを確認することができませんでした。後ほど再度お試しください", - "console.containers.device-onboarding-form.messages.classCapabilities": "LoRaWANクラスの機能追加", - "console.containers.device-onboarding-form.messages.afterRegistration": "登録完了後", - "console.containers.device-onboarding-form.messages.singleRegistration": "登録されたエンドデバイスを表示", - "console.containers.device-onboarding-form.messages.multipleRegistration": "このタイプのエンドデバイスをもう1台登録", - "console.containers.device-onboarding-form.messages.createSuccess": "エンドデバイス登録済み", - "console.containers.device-onboarding-form.messages.onboardingDisabled": "デバイスのオンボーディングは、Network Server、Application Server、Join Serverが有効になっているデプロイメントでのみ実行可能です。個々のコンポーネントにデバイスを登録するには、CLIを使用してください", - "console.containers.device-onboarding-form.messages.pingSlotDataRateTitle": "Pingスロットのデータレート", - "console.containers.device-onboarding-form.messages.rx2DataRateIndexTitle": "Rx2 データレート", - "console.containers.device-onboarding-form.messages.defaultNetworksSettings": "ネットワークのデフォルトMAC設定を使用", - "console.containers.device-onboarding-form.messages.clusterSettings": "クラスター設定", - "console.containers.device-onboarding-form.messages.networkDefaults": "ネットワークのデフォルト", - "console.containers.device-onboarding-form.messages.hasEndDeviceQR": "あなたのエンドデバイスにLoRaWAN®デバイス識別QRコードはありますか?それをスキャンすることで、オンボーディングをスピードアップすることができます", - "console.containers.device-onboarding-form.messages.deviceGuide": "デバイス登録のヘルプ", - "console.containers.device-onboarding-form.messages.deviceInfo": "QRコードデータを発見", - "console.containers.device-onboarding-form.messages.resetQRCodeData": "QRコードデータをリセット", - "console.containers.device-onboarding-form.messages.resetConfirm": "本当にQRコードデータを破棄していいのですか?スキャンした端末は登録されず、フォームがリセットされま", - "console.containers.device-onboarding-form.messages.scanSuccess": "QRコードの読み取りが成功しました", - "console.containers.device-onboarding-form.provisioning-form-section.claiming-form-section.validation-schema.validateCode": "クレーム認証コードは数字と文字のみで構成されている必要があります", - "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.advancedSectionTitle": "高度なアクティベーション、LoRaWANクラス、クラスタの設定を表示します", - "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.classA": "なし(クラスAのみ)", - "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.classB": "クラスB(ビーコン)", - "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.classC": "クラスC(連続使用)", - "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.classBandC": "クラスBとクラスC", - "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.skipJsRegistration": "ジョインサーバーでの登録をスキップ", - "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.multicastClassCapabilities": "マルチキャスト・ダウンリンク用LoRaWANクラス", - "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.register": "手動で登録", - "console.containers.device-onboarding-form.warning-tooltip.desiredDescription": "The network will use a different desired value of {value} for this property.", - "console.containers.device-onboarding-form.warning-tooltip.sessionDescription": "ABP 装置は、セッションと MAC 設定でパーソナライズされます。これらのMAC設定は現在のパラメータとみなされ、ここで入力された設定と正確に一致しなければなりません。ネットワークサーバーは、LoRaWAN MACコマンドでMAC状態を希望する状態に変更するために希望するパラメータを使用します。エンドデバイスを登録した後に、一般設定ページを使用して希望する設定を更新することができます", + "console.containers.device-onboarding-form.messages.endDeviceType": "", + "console.containers.device-onboarding-form.messages.provisioningTitle": "", + "console.containers.device-onboarding-form.messages.inputMethod": "", + "console.containers.device-onboarding-form.messages.inputMethodDeviceRepo": "", + "console.containers.device-onboarding-form.messages.inputMethodManual": "", + "console.containers.device-onboarding-form.messages.continueManual": "", + "console.containers.device-onboarding-form.messages.continueJoinEui": "", + "console.containers.device-onboarding-form.messages.changeDeviceType": "", + "console.containers.device-onboarding-form.messages.changeDeviceTypeButton": "", + "console.containers.device-onboarding-form.messages.confirmedRegistration": "", + "console.containers.device-onboarding-form.messages.confirmedClaiming": "", + "console.containers.device-onboarding-form.messages.cannotConfirmEui": "", + "console.containers.device-onboarding-form.messages.classCapabilities": "", + "console.containers.device-onboarding-form.messages.afterRegistration": "", + "console.containers.device-onboarding-form.messages.singleRegistration": "", + "console.containers.device-onboarding-form.messages.multipleRegistration": "", + "console.containers.device-onboarding-form.messages.createSuccess": "", + "console.containers.device-onboarding-form.messages.onboardingDisabled": "", + "console.containers.device-onboarding-form.messages.pingSlotDataRateTitle": "", + "console.containers.device-onboarding-form.messages.rx2DataRateIndexTitle": "", + "console.containers.device-onboarding-form.messages.defaultNetworksSettings": "", + "console.containers.device-onboarding-form.messages.clusterSettings": "", + "console.containers.device-onboarding-form.messages.networkDefaults": "", + "console.containers.device-onboarding-form.messages.hasEndDeviceQR": "", + "console.containers.device-onboarding-form.messages.deviceGuide": "", + "console.containers.device-onboarding-form.messages.deviceInfo": "", + "console.containers.device-onboarding-form.messages.resetQRCodeData": "", + "console.containers.device-onboarding-form.messages.resetConfirm": "", + "console.containers.device-onboarding-form.messages.scanSuccess": "", + "console.containers.device-onboarding-form.provisioning-form-section.claiming-form-section.validation-schema.validateCode": "", + "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.advancedSectionTitle": "", + "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.classA": "", + "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.classB": "", + "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.classC": "", + "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.classBandC": "", + "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.skipJsRegistration": "", + "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.multicastClassCapabilities": "", + "console.containers.device-onboarding-form.type-form-section.manual-form-section.advanced-settings-section.register": "", + "console.containers.device-onboarding-form.warning-tooltip.desiredDescription": "", + "console.containers.device-onboarding-form.warning-tooltip.sessionDescription": "", "console.containers.device-overview-header.index.addBookmarkFail": "", "console.containers.device-overview-header.index.removeBookmarkFail": "", "console.containers.device-overview-header.index.uplinkDownlinkTooltip": "", @@ -498,26 +498,26 @@ "console.containers.device-overview-header.index.macStateError": "", "console.containers.device-overview-header.index.sensitiveDataWarning": "", "console.containers.device-overview-header.index.noSessionWarning": "", - "console.containers.device-payload-formatters.messages.defaultFormatter": "こちら をクリックすると、このアプリケーションのデフォルトのペイロードフォーマッターを変更できます", - "console.containers.device-payload-formatters.messages.mayNotViewLink": "このアプリケーションのリンク情報を表示することは許可されていません。これには、このアプリケーションのデフォルトのペイロードフォーマッタを見ることも含まれます", + "console.containers.device-payload-formatters.messages.defaultFormatter": "", + "console.containers.device-payload-formatters.messages.mayNotViewLink": "", "console.containers.device-profile-section.device-card.index.productWebsite": "", "console.containers.device-profile-section.device-card.index.classA": "", "console.containers.device-profile-section.device-card.index.classB": "", "console.containers.device-profile-section.device-card.index.classC": "", - "console.containers.device-profile-section.device-selection.band-select.index.title": "プロフィール(リージョン)", + "console.containers.device-profile-section.device-selection.band-select.index.title": "", "console.containers.device-profile-section.device-selection.brand-select.index.title": "", "console.containers.device-profile-section.device-selection.brand-select.index.noOptionsMessage": "", "console.containers.device-profile-section.device-selection.fw-version-select.index.title": "", "console.containers.device-profile-section.device-selection.hw-version-select.index.title": "", "console.containers.device-profile-section.device-selection.model-select.index.noOptionsMessage": "", - "console.containers.device-profile-section.hints.other-hint.hintTitle": "お客様のエンドデバイスはすぐに追加されます!", - "console.containers.device-profile-section.hints.other-hint.hintMessage": "申し訳ありませんが、あなたのデバイスはまだLoRaWANデバイスリポジトリの一部ではありません。エンドデバイスの製造元が提供する情報(製品のデータシートなど)を使用して、上記のenter end device specifics manuallyオプションを使用することができます。また、デバイスの追加に関するドキュメントも参照してください", - "console.containers.device-profile-section.hints.progress-hint.hintMessage": "あなたの正確なエンドデバイスを見つけることができませんか? ここで助けを得て、上のオプションでエンドデバイスの仕様を手動で入力してみてください。", - "console.containers.device-profile-section.hints.progress-hint.hintNoSupportMessage": "あなたの正確なエンドデバイスを見つけることができませんか? 上のオプションでエンドデバイスの仕様を手動で入力してみてください", - "console.containers.device-template-format-select.index.title": "ファイルフォーマット", - "console.containers.device-template-format-select.index.warning": "エンドデバイスのテンプレートフォーマットが利用できません", + "console.containers.device-profile-section.hints.other-hint.hintTitle": "", + "console.containers.device-profile-section.hints.other-hint.hintMessage": "", + "console.containers.device-profile-section.hints.progress-hint.hintMessage": "", + "console.containers.device-profile-section.hints.progress-hint.hintNoSupportMessage": "", + "console.containers.device-template-format-select.index.title": "", + "console.containers.device-template-format-select.index.warning": "", "console.containers.devices-panel.index.recentDevices": "", - "console.containers.devices-table.index.otherClusterTooltip": "このエンドデバイスは、別のクラスタ(`{host}`)に登録されています。このデバイスにアクセスするには、このエンドデバイスが登録されているクラスタのコンソールを使用します", + "console.containers.devices-table.index.otherClusterTooltip": "", "console.containers.documentation-dashboard-panel.index.tts": "", "console.containers.documentation-dashboard-panel.index.reference": "", "console.containers.documentation-dashboard-panel.index.gettingStarted": "", @@ -626,8 +626,8 @@ "console.containers.gateway-managed-gateway.wifi-profiles.overview.deleteFail": "", "console.containers.gateway-managed-gateway.wifi-profiles.overview.deleteModalMessage": "", "console.containers.gateway-onboarding-form.gateway-provisioning-form.gateway-claim-form-section.index.claimWarning": "", - "console.containers.gateway-onboarding-form.gateway-provisioning-form.gateway-registration-form-section.index.requireAuthenticatedConnectionDescription": "{packetBrokerURL}など、他のネットワーク参加者が見ることができる情報を選択します", - "console.containers.gateway-onboarding-form.gateway-provisioning-form.gateway-registration-form-section.index.shareGatewayInfoDescription": "ゲートウェイが{loraBasicStationURL}で駆動している場合など、このオプションを選択します", + "console.containers.gateway-onboarding-form.gateway-provisioning-form.gateway-registration-form-section.index.requireAuthenticatedConnectionDescription": "", + "console.containers.gateway-onboarding-form.gateway-provisioning-form.gateway-registration-form-section.index.shareGatewayInfoDescription": "", "console.containers.gateway-onboarding-form.gateway-provisioning-form.gateway-registration-form-section.validation-schema.validateEntry": "", "console.containers.gateway-onboarding-form.gateway-provisioning-form.index.continue": "", "console.containers.gateway-onboarding-form.gateway-provisioning-form.index.emtyEui": "", @@ -656,17 +656,17 @@ "console.containers.gateway-status-panel.transmissions.noDataYet": "", "console.containers.gateway-status-panel.transmissions.established": "", "console.containers.gateway-status-panel.transmissions.notEstablished": "", - "console.containers.gateways-table.index.restoreSuccess": "ゲートウェイが復旧", - "console.containers.gateways-table.index.restoreFail": "エラーが発生し、ゲートウェイを復元することができませんでした", - "console.containers.gateways-table.index.purgeSuccess": "ゲートウェイをパージ", - "console.containers.gateways-table.index.purgeFail": "エラーが発生したため、ゲートウェイをパージすることができませんでした", + "console.containers.gateways-table.index.restoreSuccess": "", + "console.containers.gateways-table.index.restoreFail": "", + "console.containers.gateways-table.index.purgeSuccess": "", + "console.containers.gateways-table.index.purgeFail": "", "console.containers.header.bookmarks-dropdown.noBookmarks": "", "console.containers.header.bookmarks-dropdown.noBookmarksDescription": "", "console.containers.header.bookmarks-dropdown.threshold": "", "console.containers.header.notifications-dropdown.description": "", "console.containers.header.notifications-dropdown.noNotifications": "", "console.containers.header.notifications-dropdown.noNotificationsDescription": "", - "console.containers.invite-user-form.index.invitationsDescription": "電子メールアドレスを提供することで、このネットワークにユーザーを招待することができます。その後、その人には、あなたのネットワークに参加するための方法が書かれたメールが届きます", + "console.containers.invite-user-form.index.invitationsDescription": "", "console.containers.latest-decoded-payload-panel.index.latestDecodedPayload": "", "console.containers.latest-decoded-payload-panel.index.source": "", "console.containers.latest-decoded-payload-panel.index.seeInLiveData": "", @@ -674,32 +674,32 @@ "console.containers.latest-decoded-payload-panel.index.rssi": "", "console.containers.latest-decoded-payload-panel.index.snr": "", "console.containers.latest-decoded-payload-panel.index.noRecentActivityDescription": "", - "console.containers.log-back-in-modal.index.modalTitle": "もう一度サインインしてください", - "console.containers.log-back-in-modal.index.modalMessage": "コンソールからサインアウトされました。リロードを押して、コンソールに再度ログインすることができます", - "console.containers.log-back-in-modal.index.buttonMessage": "リロード", - "console.containers.lora-cloud-gls-form.index.tokenDescription": "LoRa Cloud内で設定されたGeolocationアクセストークン", - "console.containers.lora-cloud-gls-form.index.deleteWarning": "LoRaCloud Geolocationトークンを本当に削除しますか?この操作は元に戻せません", - "console.containers.lora-cloud-gls-form.index.queryType": "クエリータイプ", - "console.containers.lora-cloud-gls-form.index.queryTypeDescription": "どのようなジオロケーションクエリーを使用すべきですか", - "console.containers.lora-cloud-gls-form.index.multiFrameDescription": "マルチフレームルックアップを有効にして精度を上げます", - "console.containers.lora-cloud-gls-form.index.multiFrameWindowSize": "マルチフレームのウィンドウサイズ", - "console.containers.lora-cloud-gls-form.index.multiFrameWindowSizeDescription": "リクエストの一部として送信する履歴メッセージの数", - "console.containers.lora-cloud-gls-form.index.multiFrameTimeWindow": "マルチフレーム用タイムウィンドウ", - "console.containers.lora-cloud-gls-form.index.multiFrameTimeWindowDescription": "考慮される履歴メッセージの最大年齢を分単位で指定", - "console.containers.lora-cloud-gls-form.index.enableMultiFrame": "マルチフレームの有効化", - "console.containers.lora-cloud-ms-form.index.tokenDescription": "LoRa Cloud内で設定されたデバイス&アプリケーションサービスアクセストークン", - "console.containers.lora-cloud-ms-form.index.fPortSetTitle": "FPortセット", - "console.containers.lora-cloud-ms-form.index.fPortSetDescription": "LoRa Cloud Modemサービスで使用するF-Port値(1-223)のカンマ区切りリスト", - "console.containers.lora-cloud-ms-form.index.modemEncoding": "LoRa Edge参照トラッカー(Modem-E)エンコーディング", - "console.containers.lora-cloud-ms-form.index.deleteWarning": "本当にLoRa Cloud ModemおよびGeolocationサービストークンを削除しますか?この操作は元に戻すことができません。", - "console.containers.lora-cloud-ms-form.index.fPortSetValidationFormat": "FPortは1から223の間の数値、または1から223の間の数値のカンマ区切りリストでなければなりません", - "console.containers.move-away-modal.move-away-modal.modalTitle": "ナビゲーション確認", - "console.containers.move-away-modal.move-away-modal.modalMessage": "本当にこのままでよいのですか?あなたの現在の変更はまだ保存されていません", - "console.containers.network-information-container.index.openSourceInfo": "現在、The Things Stack Open Sourceを使用しています。The Things Stack Cloudを使用することで、さらなる機能を利用できます。", - "console.containers.network-information-container.index.plansButton": "The Things Stack Cloudを始めましょう", - "console.containers.network-information-container.registry-totals.applicationsUsed": "使用アプリケーション", - "console.containers.network-information-container.registry-totals.gatewaysUsed": "使用ゲートウェイ", - "console.containers.network-information-container.registry-totals.registeredUsers": "登録ユーザー", + "console.containers.log-back-in-modal.index.modalTitle": "", + "console.containers.log-back-in-modal.index.modalMessage": "", + "console.containers.log-back-in-modal.index.buttonMessage": "", + "console.containers.lora-cloud-gls-form.index.tokenDescription": "", + "console.containers.lora-cloud-gls-form.index.deleteWarning": "", + "console.containers.lora-cloud-gls-form.index.queryType": "", + "console.containers.lora-cloud-gls-form.index.queryTypeDescription": "", + "console.containers.lora-cloud-gls-form.index.multiFrameDescription": "", + "console.containers.lora-cloud-gls-form.index.multiFrameWindowSize": "", + "console.containers.lora-cloud-gls-form.index.multiFrameWindowSizeDescription": "", + "console.containers.lora-cloud-gls-form.index.multiFrameTimeWindow": "", + "console.containers.lora-cloud-gls-form.index.multiFrameTimeWindowDescription": "", + "console.containers.lora-cloud-gls-form.index.enableMultiFrame": "", + "console.containers.lora-cloud-ms-form.index.tokenDescription": "", + "console.containers.lora-cloud-ms-form.index.fPortSetTitle": "", + "console.containers.lora-cloud-ms-form.index.fPortSetDescription": "", + "console.containers.lora-cloud-ms-form.index.modemEncoding": "", + "console.containers.lora-cloud-ms-form.index.deleteWarning": "", + "console.containers.lora-cloud-ms-form.index.fPortSetValidationFormat": "", + "console.containers.move-away-modal.move-away-modal.modalTitle": "", + "console.containers.move-away-modal.move-away-modal.modalMessage": "", + "console.containers.network-information-container.index.openSourceInfo": "", + "console.containers.network-information-container.index.plansButton": "", + "console.containers.network-information-container.registry-totals.applicationsUsed": "", + "console.containers.network-information-container.registry-totals.gatewaysUsed": "", + "console.containers.network-information-container.registry-totals.registeredUsers": "", "console.containers.notifications-dashboard-panel.index.noNotificationsDescription": "", "console.containers.notifications.index.seeArchived": "", "console.containers.notifications.index.seeAll": "", @@ -723,25 +723,25 @@ "console.containers.oauth-clients-table.index.restoreFail": "", "console.containers.oauth-clients-table.index.purgeSuccess": "", "console.containers.oauth-clients-table.index.purgeFail": "", - "console.containers.organization-form.form.orgDescPlaceholder": "新しい組織の説明", - "console.containers.organization-form.form.orgDescDescription": "組織の説明(任意)。組織に関するメモを保存するためにも使用できます", - "console.containers.organization-form.form.orgIdPlaceholder": "my-new-organization", - "console.containers.organization-form.form.orgNamePlaceholder": "私の新組織", - "console.containers.organization-form.form.adminContactDescription": "この組織の管理者連絡先情報。通常、組織に関する管理的な質問をするべき連絡先を示すために使用されます。", - "console.containers.organization-form.form.techContactDescription": "この組織の技術連絡先情報。通常、組織に関する技術/セキュリティの質問をするべき連絡先を示すために使用されます。", - "console.containers.organization-form.update.deleteOrg": "組織を削除", - "console.containers.organization-form.update.updateSuccess": "組織が更新されました", - "console.containers.organization-form.update.deleteSuccess": "削除された組織", - "console.containers.organizations-table.index.restoreSuccess": "復元された組織", - "console.containers.organizations-table.index.restoreFail": "エラーが発生し、組織を復元することができませんでした", - "console.containers.organizations-table.index.purgeSuccess": "パージされた組織", - "console.containers.organizations-table.index.purgeFail": "エラーが発生したため、組織をパージすることができませんでした", + "console.containers.organization-form.form.orgDescPlaceholder": "", + "console.containers.organization-form.form.orgDescDescription": "", + "console.containers.organization-form.form.orgIdPlaceholder": "", + "console.containers.organization-form.form.orgNamePlaceholder": "", + "console.containers.organization-form.form.adminContactDescription": "", + "console.containers.organization-form.form.techContactDescription": "", + "console.containers.organization-form.update.deleteOrg": "", + "console.containers.organization-form.update.updateSuccess": "", + "console.containers.organization-form.update.deleteSuccess": "", + "console.containers.organizations-table.index.restoreSuccess": "", + "console.containers.organizations-table.index.restoreFail": "", + "console.containers.organizations-table.index.purgeSuccess": "", + "console.containers.organizations-table.index.purgeFail": "", "console.containers.owners-select.index.title": "", "console.containers.owners-select.index.warning": "", - "console.containers.packet-broker-networks-table.index.nonDefaultPolicies": "デフォルトでないポリシーを持つネットワーク", - "console.containers.packet-broker-networks-table.index.search": "テナントID、テナント名で検索", - "console.containers.packet-broker-networks-table.index.forwarderPolicy": "私たちに対する彼らのルーティングポリシー", - "console.containers.packet-broker-networks-table.index.homeNetworkPolicy": "それらに対する当社のルーティングポリシー", + "console.containers.packet-broker-networks-table.index.nonDefaultPolicies": "", + "console.containers.packet-broker-networks-table.index.search": "", + "console.containers.packet-broker-networks-table.index.forwarderPolicy": "", + "console.containers.packet-broker-networks-table.index.homeNetworkPolicy": "", "console.containers.profile-settings-form.messages.imageProvided": "", "console.containers.profile-settings-form.messages.profilePicture": "", "console.containers.profile-settings-form.messages.successMessage": "", @@ -761,8 +761,8 @@ "console.containers.profile-settings-form.messages.purgeWarning": "", "console.containers.profile-settings-form.messages.deleteTitle": "", "console.containers.profile-settings-form.messages.deleteConfirmMessage": "", - "console.containers.pubsub-formats-select.index.warning": "Pub/Subフォーマットが無効です", - "console.containers.pubsubs-table.index.host": "サーバーホスト", + "console.containers.pubsub-formats-select.index.warning": "", + "console.containers.pubsubs-table.index.host": "", "console.containers.sessions-table.index.deleteSessionSuccess": "", "console.containers.sessions-table.index.deleteSessionError": "", "console.containers.sessions-table.index.removeButtonMessage": "", @@ -795,198 +795,198 @@ "console.containers.top-entities-dashboard-panel.top-gateways.index.emptyMessage": "", "console.containers.top-entities-dashboard-panel.top-gateways.index.emptyDescription": "", "console.containers.top-entities-dashboard-panel.top-gateways.index.emptyAction": "", - "console.containers.user-data-form.edit.deleteWarning": "これにより、このアカウントは永久に削除され、再登録のためにユーザーIDおよび電子メールがロックされます。このユーザーが所有し、他の協力者がいない関連エンティティ(ゲートウェイ、アプリケーション、エンドデバイスなど)は接続不能となり、同じIDまたはEUIを持つエンティティを再び登録することはできなくなります。このようなエンティティを継続して使用する場合は、必ず新しいコラボレーターを割り当ててください", - "console.containers.user-data-form.edit.purgeWarning": "これにより、このアカウントは永久に削除されます。このユーザーが所有し、他の協力者がいない関連エンティティ(ゲートウェイ、アプリケーション、エンドデバイスなど)は接続不能となり、同じIDまたはEUIを持つエンティティを再び登録することはできなくなります。このようなエンティティの使用を継続する場合は、必ず新しい共同作業者を割り当ててください", - "console.containers.user-data-form.edit.deleteConfirmMessage": "確認のため、このユーザーのユーザーIDを入力してください", - "console.containers.user-data-form.edit.updateSuccess": "ユーザーが更新しました", - "console.containers.user-data-form.edit.deleteSuccess": "ユーザー削除", - "console.containers.users-table.index.invite": "ユーザーを招待", - "console.containers.users-table.index.revokeInvitation": "この招待を取り消し", - "console.containers.users-table.index.sentAt": "送信済み", - "console.containers.users-table.index.revokeSuccess": "招待状は正常に削除されました", - "console.containers.users-table.index.revokeError": "エラーが発生したため、招待を取り消すことができませんでした", - "console.containers.webhook-formats-select.index.warning": "Webhookフォーマットが無効です", - "console.containers.webhooks-table.index.templateId": "テンプレートID", - "console.containers.webhooks-table.index.healthy": "ヘルシー", - "console.containers.webhooks-table.index.pending": "保留中", - "console.containers.webhooks-table.index.requestsFailing": "リクエスト失敗", - "console.lib.events.definitions.synthetic.error.unknown:preview": "未知のエラーが発生し、1つ以上のイベントを取得できませんでした", - "console.lib.events.definitions.synthetic.error.unknown:details": "コンソールでイベントストリームデータを処理中に予期しないエラーが発生しました。その結果、イベントデータが(正しく)表示されなかった可能性があります。これは内部エラーであり、ゲートウェイやエンドデバイスの故障を意味するものではありません。", - "console.lib.events.definitions.synthetic.error.network_error:type": "ネットワークエラー", - "console.lib.events.definitions.synthetic.error.network_error:preview": "ネットワークエラーによりストリーム接続が失われました。", - "console.lib.events.definitions.synthetic.error.network_error:details": "ホストマシンのネットワーク接続が中断されたため、コンソールではストリームイベントを取得できませんでした。これは、ホスト マシンが Wi-Fi ネットワークを切り替えたり、信号強度の低下が発生したりするなど、さまざまな原因が考えられます。ストリームが切断されないように、インターネット接続を確認し、安定したインターネット接続を確保してください。インターネット接続が再確立されると、ストリームは自動的に再接続されます。", - "console.lib.events.definitions.synthetic.status.reconnecting:type": "再接続", - "console.lib.events.definitions.synthetic.status.reconnecting:preview": "再接続を試みてます...", - "console.lib.events.definitions.synthetic.status.reconnecting:details": "接続が中断された場合、コンソールは定期的にイベントストリームへの再接続を試みます", - "console.lib.events.definitions.synthetic.status.reconnected:type": "ストリーム再接続", - "console.lib.events.definitions.synthetic.status.reconnected:preview": "ストリーム接続が再確立されました", - "console.lib.events.definitions.synthetic.status.reconnected:details": "コンソールはインターネットに再接続し、イベントストリームを再開することができました。それ以降のイベントデータは受信され、表示されます。ネットワーク障害中に発生した可能性のあるイベントデータは再配信されませんのでご注意ください。", - "console.lib.events.definitions.synthetic.status.closed:type": "ストリーム接続が閉じています", - "console.lib.events.definitions.synthetic.status.closed:preview": "ストリームプロバイダによって接続が閉じられました", - "console.lib.events.definitions.synthetic.status.closed:details": "コンソールはストリームプロバイダからのクローズシグナルを受信しました。これは通常、バックエンドサーバーがシャットダウンしたことを意味します。これには、定期的なメンテナンスや、強制再起動の原因となった誤動作など、さまざまな原因が考えられます。ストリームプロバイダが再び利用可能になると、Consoleは自動的に再接続します。", - "console.lib.events.definitions.synthetic.status.cleared:type": "イベントクリア", - "console.lib.events.definitions.synthetic.status.cleared:preview": "イベントリストがクリアされました", - "console.lib.events.definitions.synthetic.status.cleared:details": "表示されているイベントのリストがクリアされました", - "console.lib.events.definitions.synthetic.status.paused:type": "ストリームの一時停止", - "console.lib.events.definitions.synthetic.status.paused:preview": "イベントストリームが一時停止されました", - "console.lib.events.definitions.synthetic.status.paused:details": "イベントストリームはユーザーによって一時停止されました。ストリームが再開されるまで、それ以降のイベントデータは表示されません", - "console.lib.events.definitions.synthetic.status.resumed:type": "ストリーム再開", - "console.lib.events.definitions.synthetic.status.resumed:preview": "イベントストリームは一時停止後に再開されました", - "console.lib.events.definitions.synthetic.status.resumed:details": "イベントストリームはユーザーによって再開され、新しい後続のイベントデータを受信します。ストリームの一時停止中に放出された可能性のあるイベントデータは再配信されないことに注意してください", - "console.lib.events.definitions.synthetic.status.filter_enabled:type": "フィルター有効", - "console.lib.events.definitions.synthetic.status.filter_enabled:preview": "イベントフィルターが有効になりました", - "console.lib.events.definitions.synthetic.status.filter_enabled:details": "イベントストリームがフィルタリングされるようになり、一部のイベントタイプが抑制される可能性があることを意味します。現在有効になっているフィルタリングの詳細については、以下の詳細を参照してください", - "console.lib.events.definitions.synthetic.status.filter_disabled:type": "フィルター無効", - "console.lib.events.definitions.synthetic.status.filter_disabled:preview": "以前に設定したイベントフィルターが無効になりました", - "console.lib.events.definitions.synthetic.status.filter_disabled:details": "イベントストリームがフィルタリングされなくなります。つまり、このエンティティのイベントストリームから出るすべてのイベントが表示されることになります", - "console.lib.packet-broker.messages.applicationDataAllowDesc": "FPortが1~255のダウンリンクメッセージを許可します", - "console.lib.packet-broker.messages.applicationDataDesc": "FPort1-255でアップリンクメッセージを転送します", - "console.lib.packet-broker.messages.joinAcceptDesc": "ジョインアクセプトメッセージを許可", - "console.lib.packet-broker.messages.joinRequest": "ジョイン", - "console.lib.packet-broker.messages.joinRequestDesc": "ジョインリクエストメッセージの転送", - "console.lib.packet-broker.messages.localizationInformation": "ローカライズ情報", - "console.lib.packet-broker.messages.localizationInformationDesc": "フォワードゲートウェイの位置、RSSI、SNR、ファインタイムスタンプ", - "console.lib.packet-broker.messages.macDataAllowDesc": "FPortが0であるダウンリンクメッセージを許可します", - "console.lib.packet-broker.messages.macDataDesc": "FPort 0 でアップリンクメッセージを転送します", - "console.lib.packet-broker.messages.signalQualityInformation": "信号品質に関する情報", - "console.lib.packet-broker.messages.signalQualityInformationDesc": "RSSIとSNRを転送します", - "console.lib.packet-broker.messages.forwardsJoinRequest": "ジョインリクエストメッセージは転送されます", - "console.lib.packet-broker.messages.doesNotForwardJoinRequest": "ジョインリクエストメッセージは転送されません", - "console.lib.packet-broker.messages.forwardsMacData": "MACデータは転送されます", - "console.lib.packet-broker.messages.doesNotForwardMacData": "MACデータは転送されません", - "console.lib.packet-broker.messages.forwardsApplicationData": "アプリケーションデータを転送します", - "console.lib.packet-broker.messages.doesNotForwardApplicationData": "アプリケーションデータは転送されません", - "console.lib.packet-broker.messages.forwardsSignalQuality": "信号の品質情報を転送します", - "console.lib.packet-broker.messages.doesNotForwardSignalQuality": "信号の品質情報は転送されません", - "console.lib.packet-broker.messages.forwardsLocalization": "ローカライズ情報を転送します", - "console.lib.packet-broker.messages.doesNotForwardLocalization": "ローカライズ情報は転送されません", - "console.lib.packet-broker.messages.allowsJoinAccept": "ジョインアクセプトメッセージを許可します", - "console.lib.packet-broker.messages.doesNotAllowJoinAccept": "ジョインアクセプトメッセージは使用不可", - "console.lib.packet-broker.messages.allowsMacData": "MACデータの使用可", - "console.lib.packet-broker.messages.doesNotAllowMacData": "MACデータの使用不可", - "console.lib.packet-broker.messages.allowsApplicationData": "アプリケーションデータの使用可", - "console.lib.packet-broker.messages.doesNotAllowApplicationData": "アプリケーションデータの使用不可", - "console.lib.packet-broker.messages.uplinkPolicies": "この最上段には、このネットワークのアップリンク転送ポリシーが表示されています", - "console.lib.packet-broker.messages.downlinkPolicies": "この下段には、このネットワークのダウンリンクのポリシーが示されています", - "console.lib.packet-broker.messages.gatewayAntennaPlacementLabel": "アンテナの配置", - "console.lib.packet-broker.messages.gatewayAntennaPlacementDescription": "アンテナ配置を表示(屋内/屋外)", - "console.lib.packet-broker.messages.gatewayAntennaCountLabel": "アンテナ数", - "console.lib.packet-broker.messages.gatewayFineTimestampsLabel": "細かいタイムスタンプ", - "console.lib.packet-broker.messages.gatewayFineTimestampsDescription": "ゲートウェイが細かいタイムスタンプを生成するかどうか", - "console.lib.packet-broker.messages.gatewayContactInfoDescription": "ゲートウェイの所有者または運営者に連絡する手段を示します", - "console.lib.packet-broker.messages.gatewayStatusDescription": "ゲートウェイがオンラインかオフラインかを表示します", - "console.lib.packet-broker.messages.gatewayPacketRatesLabel": "パケットレート", - "console.lib.packet-broker.messages.gatewayPacketRatesDescription": "受信・送信パケットレート", - "console.store.middleware.logics.packet-broker.unauthenticatedErrorTitle": "オーソライズできません", - "console.store.middleware.logics.packet-broker.unauthenticatedErrorMessage": "コンソールは、Packet Brokerエージェントへのリクエストを認証することができません。The Things StackのPacket Broker機能が正しく設定されていることを確認してください。上記のドキュメントを参照することで、より詳細なガイダンスが得られます", - "console.store.middleware.logics.users.errEmailValidationActionSuccess": "確認メールが送信されました(迷惑メールフォルダも確認してください)", - "console.store.middleware.logics.users.errEmailValidationActionFailure": "エラーが発生し、確認メールを送信できませんでした。", - "console.store.middleware.logics.users.errEmailValidationAlreadySent": "最近、あなたのメールアドレスに確認メールが送信されました。迷惑メールフォルダも確認してください。", - "console.views.admin-packet-broker.messages.packetBrokerInfoText": "Packet Brokerは、他のLoRaWANネットワークとトラフィックを交換(ピアリング)することで、カバレッジを共有し、ネットワーク全体のパフォーマンスを向上させるために使用することができます", - "console.views.admin-packet-broker.messages.packetBrokerWebsite": "Packer Brokerのサイト", + "console.containers.user-data-form.edit.deleteWarning": "", + "console.containers.user-data-form.edit.purgeWarning": "", + "console.containers.user-data-form.edit.deleteConfirmMessage": "", + "console.containers.user-data-form.edit.updateSuccess": "", + "console.containers.user-data-form.edit.deleteSuccess": "", + "console.containers.users-table.index.invite": "", + "console.containers.users-table.index.revokeInvitation": "", + "console.containers.users-table.index.sentAt": "", + "console.containers.users-table.index.revokeSuccess": "", + "console.containers.users-table.index.revokeError": "", + "console.containers.webhook-formats-select.index.warning": "", + "console.containers.webhooks-table.index.templateId": "", + "console.containers.webhooks-table.index.healthy": "", + "console.containers.webhooks-table.index.pending": "", + "console.containers.webhooks-table.index.requestsFailing": "", + "console.lib.events.definitions.synthetic.error.unknown:preview": "", + "console.lib.events.definitions.synthetic.error.unknown:details": "", + "console.lib.events.definitions.synthetic.error.network_error:type": "", + "console.lib.events.definitions.synthetic.error.network_error:preview": "", + "console.lib.events.definitions.synthetic.error.network_error:details": "", + "console.lib.events.definitions.synthetic.status.reconnecting:type": "", + "console.lib.events.definitions.synthetic.status.reconnecting:preview": "", + "console.lib.events.definitions.synthetic.status.reconnecting:details": "", + "console.lib.events.definitions.synthetic.status.reconnected:type": "", + "console.lib.events.definitions.synthetic.status.reconnected:preview": "", + "console.lib.events.definitions.synthetic.status.reconnected:details": "", + "console.lib.events.definitions.synthetic.status.closed:type": "", + "console.lib.events.definitions.synthetic.status.closed:preview": "", + "console.lib.events.definitions.synthetic.status.closed:details": "", + "console.lib.events.definitions.synthetic.status.cleared:type": "", + "console.lib.events.definitions.synthetic.status.cleared:preview": "", + "console.lib.events.definitions.synthetic.status.cleared:details": "", + "console.lib.events.definitions.synthetic.status.paused:type": "", + "console.lib.events.definitions.synthetic.status.paused:preview": "", + "console.lib.events.definitions.synthetic.status.paused:details": "", + "console.lib.events.definitions.synthetic.status.resumed:type": "", + "console.lib.events.definitions.synthetic.status.resumed:preview": "", + "console.lib.events.definitions.synthetic.status.resumed:details": "", + "console.lib.events.definitions.synthetic.status.filter_enabled:type": "", + "console.lib.events.definitions.synthetic.status.filter_enabled:preview": "", + "console.lib.events.definitions.synthetic.status.filter_enabled:details": "", + "console.lib.events.definitions.synthetic.status.filter_disabled:type": "", + "console.lib.events.definitions.synthetic.status.filter_disabled:preview": "", + "console.lib.events.definitions.synthetic.status.filter_disabled:details": "", + "console.lib.packet-broker.messages.applicationDataAllowDesc": "", + "console.lib.packet-broker.messages.applicationDataDesc": "", + "console.lib.packet-broker.messages.joinAcceptDesc": "", + "console.lib.packet-broker.messages.joinRequest": "", + "console.lib.packet-broker.messages.joinRequestDesc": "", + "console.lib.packet-broker.messages.localizationInformation": "", + "console.lib.packet-broker.messages.localizationInformationDesc": "", + "console.lib.packet-broker.messages.macDataAllowDesc": "", + "console.lib.packet-broker.messages.macDataDesc": "", + "console.lib.packet-broker.messages.signalQualityInformation": "", + "console.lib.packet-broker.messages.signalQualityInformationDesc": "", + "console.lib.packet-broker.messages.forwardsJoinRequest": "", + "console.lib.packet-broker.messages.doesNotForwardJoinRequest": "", + "console.lib.packet-broker.messages.forwardsMacData": "", + "console.lib.packet-broker.messages.doesNotForwardMacData": "", + "console.lib.packet-broker.messages.forwardsApplicationData": "", + "console.lib.packet-broker.messages.doesNotForwardApplicationData": "", + "console.lib.packet-broker.messages.forwardsSignalQuality": "", + "console.lib.packet-broker.messages.doesNotForwardSignalQuality": "", + "console.lib.packet-broker.messages.forwardsLocalization": "", + "console.lib.packet-broker.messages.doesNotForwardLocalization": "", + "console.lib.packet-broker.messages.allowsJoinAccept": "", + "console.lib.packet-broker.messages.doesNotAllowJoinAccept": "", + "console.lib.packet-broker.messages.allowsMacData": "", + "console.lib.packet-broker.messages.doesNotAllowMacData": "", + "console.lib.packet-broker.messages.allowsApplicationData": "", + "console.lib.packet-broker.messages.doesNotAllowApplicationData": "", + "console.lib.packet-broker.messages.uplinkPolicies": "", + "console.lib.packet-broker.messages.downlinkPolicies": "", + "console.lib.packet-broker.messages.gatewayAntennaPlacementLabel": "", + "console.lib.packet-broker.messages.gatewayAntennaPlacementDescription": "", + "console.lib.packet-broker.messages.gatewayAntennaCountLabel": "", + "console.lib.packet-broker.messages.gatewayFineTimestampsLabel": "", + "console.lib.packet-broker.messages.gatewayFineTimestampsDescription": "", + "console.lib.packet-broker.messages.gatewayContactInfoDescription": "", + "console.lib.packet-broker.messages.gatewayStatusDescription": "", + "console.lib.packet-broker.messages.gatewayPacketRatesLabel": "", + "console.lib.packet-broker.messages.gatewayPacketRatesDescription": "", + "console.store.middleware.logics.packet-broker.unauthenticatedErrorTitle": "", + "console.store.middleware.logics.packet-broker.unauthenticatedErrorMessage": "", + "console.store.middleware.logics.users.errEmailValidationActionSuccess": "", + "console.store.middleware.logics.users.errEmailValidationActionFailure": "", + "console.store.middleware.logics.users.errEmailValidationAlreadySent": "", + "console.views.admin-packet-broker.messages.packetBrokerInfoText": "", + "console.views.admin-packet-broker.messages.packetBrokerWebsite": "", "console.views.admin-packet-broker.messages.learnMore": "", "console.views.admin-packet-broker.messages.whyNetworkPeeringTitle": "", "console.views.admin-packet-broker.messages.whyNetworkPeeringText": "", "console.views.admin-packet-broker.messages.enbaling": "", - "console.views.admin-packet-broker.messages.packetBrokerDisabledDesc": "The Things Stackは、Packet Brokerを使用するための設定はされていません。Packet BrokerとピアリングするためのThe Things Stackのセットアップ方法については、上記のドキュメントリンクを参照してください", + "console.views.admin-packet-broker.messages.packetBrokerDisabledDesc": "", "console.views.admin-packet-broker.messages.enablePacketBroker": "", - "console.views.admin-packet-broker.messages.packetBrokerRegistrationDesc": "ご自宅のネットワークから、またはご自宅のネットワークへのピアリングを可能にするには、ご自宅のネットワークを登録する必要があります。これにより、お客様のネットワークがPacket Brokerに認識され、お客様のネットワークのピアリング動作を設定することができます", + "console.views.admin-packet-broker.messages.packetBrokerRegistrationDesc": "", "console.views.admin-packet-broker.messages.routingConfig": "", - "console.views.admin-packet-broker.messages.network": "ネットワーク: {network}", - "console.views.admin-packet-broker.messages.listNetwork": "ネットワーク公開で一覧表示", - "console.views.admin-packet-broker.messages.listNetworkDesc": "ネットワークをリストアップすることで、他のネットワーク管理者があなたのネットワークを見ることができます。これにより、他のネットワーク管理者は、あなたのネットワークでルーティングポリシーを簡単に設定することができます", - "console.views.admin-packet-broker.messages.unlistNetwork": "このネットワークをアンリスト化", - "console.views.admin-packet-broker.messages.confirmUnlist": "アンリストを確認", - "console.views.admin-packet-broker.messages.Are you sure you want to unlist your network in Packet Broker?{lineBreak}This will hide your network. Other network administrators will not be able to see your network to configure routing policies.": "PacketBrokerに登録されていないネットワークは、本当に登録されていないのでしょうか?他のネットワーク管理者は、ルーティングポリシーを設定するためにあなたのネットワークを見ることができなくなります", - "console.views.admin-packet-broker.messages.routingPolicyInformation": "以下のチェックボックスを使用して、ネットワークのデフォルトの転送動作を制御することができます。さらに、[ネットワーク]タブでネットワークごとのルーティングポリシーを個別に設定することもできます", - "console.views.admin-packet-broker.messages.defaultRoutingPolicySet": "デフォルトのルーティングポリシー設定", - "console.views.admin-packet-broker.messages.routingPolicySet": "ルーティングポリシーセット", - "console.views.admin-packet-broker.messages.defaultRoutingPolicy": "既定のルーティングポリシー", - "console.views.admin-packet-broker.messages.devAddressBlock": "デバイスアドレスブロック", - "console.views.admin-packet-broker.messages.devAddressBlocks": "デバイスアドレスブロック", - "console.views.admin-packet-broker.messages.lastPolicyChange": "最後の方針変更", - "console.views.admin-packet-broker.messages.networkId": "ネットワークID", - "console.views.admin-packet-broker.messages.routingPolicyFromThisNetwork": "このネットワークの当社に対するルーティングポリシー", - "console.views.admin-packet-broker.messages.routingPolicyToThisNetwork": "このネットワークに対するルーティングポリシーを設定します", - "console.views.admin-packet-broker.messages.saveRoutingPolicy": "ルーティングポリシーの保存", - "console.views.admin-packet-broker.messages.noPolicySet": "ポリシーはまだ決まっていません", - "console.views.admin-packet-broker.messages.prefixes": "プレフィクス", - "console.views.admin-packet-broker.messages.homeNetworkClusterId": "ホームネットワーククラスターID", - "console.views.admin-packet-broker.messages.backToAllNetworks": "すべてのネットワークへ戻る", - "console.views.admin-packet-broker.messages.deregisterNetwork": "このネットワークの登録解除", - "console.views.admin-packet-broker.messages.confirmDeregister": "登録解除の確認", - "console.views.admin-packet-broker.messages.Are you sure you want to deregister your network from Packet Broker?{lineBreak}This will permanently delete<.b> all routing policies and may stop traffic from flowing.{lineBreak}Traffic may still be forwarded to your network based on default routing policies configured by forwarders.": "Packet Brokerからネットワークの登録を解除してよろしいですか? {lineBreak}すべてのルーティングポリシーが永久に削除されるため、トラフィックが流れなくなる可能性があります。{lineBreak}フォワーダが設定したデフォルトのルーティングポリシーに基づき、トラフィックがネットワークに転送される可能性はあります", - "console.views.admin-packet-broker.messages.defaultGatewayVisibility": "デフォルトゲートウェイの可視化", - "console.views.admin-packet-broker.messages.gatewayVisibilityInformation": "チェックボックスを使用して、ゲートウェイの情報を表示するように制御することができます。この情報は、登録されたネットワークだけでなく、一般にも公開されることに注意してください", - "console.views.admin-packet-broker.messages.defaultGatewayVisibilitySet": "デフォルトゲートウェイの可視化設定", - "console.views.admin-packet-broker.messages.packetBrokerStatusPage": "Packet Broker ステータスページ", - "console.views.application-add.index.appDescription": "アプリケーション内では、エンドデバイスとそのネットワークデータを登録、管理することができます。デバイス群を設定した後、多くの統合オプションの1つを使用して、関連データを外部サービスに渡します。Adding Applications に関するガイドで詳しく説明しています", - "console.views.application-integrations-lora-cloud.index.loraCloudInfoText": "LoRaWANネットワークやLoRaベースのデバイスに関連する一般的なタスクのシンプルなソリューションを可能にする付加価値の高いAPIをローラクラウドが提供します。以下からLoRaCloudのインテグレーションを設定することができます", - "console.views.application-integrations-lora-cloud.index.officialLoRaCloudDocumentation": "オフィシャル LoRa Cloud ドキュメンテーション", - "console.views.application-integrations-lora-cloud.index.dasDescription": "LoRa Cloud Modem and Geolocation Servicesプロトコルを使用すると、LoRaWAN対応デバイスのアプリケーション層で共通のデバイス機能を管理することができます", - "console.views.application-integrations-lora-cloud.index.glsDescription": "LoRa Cloud Geolocationは、The Things Stackと簡単に統合でき、あらゆるLoRaベースのデバイスの位置を推定することができるシンプルなクラウドAPIです", - "console.views.application-integrations-mqtt.index.publicAddress": "パブリックアドレス", - "console.views.application-integrations-mqtt.index.publicTlsAddress": "パブリックTLSアドレス", - "console.views.application-integrations-mqtt.index.generateApiKey": "新しいAPIキーの生成", - "console.views.application-integrations-mqtt.index.goToApiKeys": "APIキーに移動", - "console.views.application-integrations-mqtt.index.mqttInfoText": "アプリケーションサーバーは、ストリーミングイベントを扱うためのMQTTサーバーを公開しています。MQTTサーバーを使用するためには、接続パスワードとして機能する新しいAPIキーを作成する必要があります。必要な権限が付与されていれば、既存のAPIキーを使用することもできます。以下の接続情報を使用して接続してください。", - "console.views.application-integrations-mqtt.index.connectionCredentials": "接続認証情報", - "console.views.application-integrations-mqtt.index.mqttIntegrations": "MQTTイングレーション", - "console.views.application-integrations-mqtt.index.officialMqttWebsite": "MQTTの公式サイト", - "console.views.application-integrations-mqtt.index.mqttServer": "MQTTサーバー", - "console.views.application-integrations-mqtt.index.host": "MQTTサーバーホスト", - "console.views.application-integrations-mqtt.index.connectionInfo": "接続情報", - "console.views.application-integrations-pubsub-edit.index.editPubsub": "Pub/Subを編集", - "console.views.application-integrations-pubsub-edit.index.updateSuccess": "Pub/Subの更新", - "console.views.application-integrations-pubsub-edit.index.deleteSuccess": "Pub/Subの削除", - "console.views.application-integrations-webhook-add-choose.index.chooseTemplate": "Webhookテンプレートの選択", - "console.views.application-integrations-webhook-add-choose.index.customTileDescription": "テンプレート無しでカスタムWebhookを作成", - "console.views.application-integrations-webhook-add-form.index.addCustomWebhook": "カスタム Webhookを追加", - "console.views.application-integrations-webhook-add-form.index.addWebhookViaTemplate": "{templateName} Webhookを追加します", - "console.views.application-integrations-webhook-add-form.index.customWebhook": "カスタム Webhook", - "console.views.application-overview.index.failedAccessOtherHostApplication": "アクセスしようとしたアプリケーションは、別のクラスタに登録されており、そのホストコンソールを使用してアクセスする必要があります", - "console.views.device-general-settings.application-server-form.index.skip": "ペイロード暗号のスキップの強制", - "console.views.device-general-settings.application-server-form.index.include": "ペイロード暗号の強制", - "console.views.device-general-settings.application-server-form.index.default": "アプリケーションのデフォルトを使用", - "console.views.device-general-settings.application-server-form.index.skipCryptoTitle": "ペイロード暗号の上書き", - "console.views.device-general-settings.messages.isTitle": "ベーシック", - "console.views.device-general-settings.messages.isDescription": "説明、クラスタ情報、メタデータ", - "console.views.device-general-settings.messages.isDescriptionMissing": "アイデンティティサーバーは利用できません", - "console.views.device-general-settings.messages.asTitle": "アプリケーションレイヤー", - "console.views.device-general-settings.messages.asDescription": "アプリケーションレイヤーの動作とセッション", - "console.views.device-general-settings.messages.asDescriptionMissing": "アプリケーションサーバーは利用できません", - "console.views.device-general-settings.messages.asDescriptionOTAA": "参加したOTAAエンドデバイスのキーのみがアプリケーションサーバに保存されます", - "console.views.device-general-settings.messages.jsTitle": "Join設定", - "console.views.device-general-settings.messages.jsDescription": "エンドデバイスのアクティベーションのためのルートキーとネットワーク設定", - "console.views.device-general-settings.messages.jsDescriptionMissing": "Joinサーバーは利用できません", - "console.views.device-general-settings.messages.jsDescriptionOTAA": "ABP/マルチキャストのエンドデバイスはJoinサーバーに保存されません", - "console.views.device-general-settings.messages.nsTitle": "ネットワークレイヤー", - "console.views.device-general-settings.messages.nsDescription": "LoRaWANネットワーク層の設定、動作、セッション", - "console.views.device-general-settings.messages.nsDescriptionMissing": "ネットワークサーバーは利用できません", - "console.views.device-general-settings.messages.deleteSuccess": "エンドデバイス削除", - "console.views.device-general-settings.messages.deleteFailure": "エラーが発生し、エンドデバイスを削除できませんでした", - "console.views.device-general-settings.messages.activationModeUnknown": "ネットワークサーバーが利用できないため、アクティベーションモードが不明です", - "console.views.device-general-settings.messages.notInCluster": "このクラスタに登録されていません", - "console.views.device-general-settings.messages.updateSuccess": "エンドデバイスの更新", - "console.views.device-general-settings.messages.keysResetWarning": "エンドデバイスのキーの閲覧は禁止されていますが、上書きは許可されています", - "console.views.device-general-settings.messages.unclaimFailure": "エラーが発生し、エンドデバイスをアンクレイムして削除することができませんでした", - "console.views.device-general-settings.messages.validateSessionKey": "{field}は0以外の値でなければなりません", - "console.views.device-general-settings.messages.resetUsedDevNonces": "使用したDevNoncesをリセット", - "console.views.device-general-settings.messages.resetUsedDevNoncesModal": "{break}{break}使用済みDevNoncesをリセットすると、過去のNoncesを使用したリプレイアタックが可能になります。エンドデバイスのNVRAMをリセットしていない限り、このオプションは使用しないでください", - "console.views.device-general-settings.messages.resetSuccess": "中古DevNoncesリセット", - "console.views.device-general-settings.messages.resetFailure": "エラーが発生し、使用中のDevNoncesをリセットすることができませんでした", - "console.views.device-general-settings.network-server-form.index.resetTitle": "セッションおよびMAC状態のリセット", - "console.views.device-general-settings.network-server-form.index.resetButtonTitle": "セッションとMACの状態をリセット", - "console.views.device-general-settings.network-server-form.index.resetSuccess": "エンドデバイスのリセット", - "console.views.device-general-settings.network-server-form.index.resetFailure": "エラーが発生し、エンドデバイスのセッションとMACの状態をリセットすることができませんでした", - "console.views.device-general-settings.network-server-form.index.modalMessage": "このエンドデバイスのセッションコンテキストとMACの状態をリセットしていいですか? これにより、以下のような影響があります:
  • For OTAA-activated end devices all session and MAC data is wiped and the end device MUST rejoin
  • For ABP-activated end devices, session keys, device address and downlink queue are preserved, while the MAC state is reset
", - "console.views.device-import.index.noTemplatesTitle": "エンドデバイスのテンプレートは見つかりませんでした", - "console.views.device-import.index.noTemplates": "現在、エンドデバイステンプレートは設定されていません。デバイス一括インポート機能を利用するために、エンドデバイステンプレートを設定してください。詳細については、ドキュメントを参照してください", - "console.views.device-location.index.locationInfoTitle": "エンドデバイスの位置設定の把握", - "console.views.device-location.index.locationInfo": "The Things Stackは、複数のソースから同時にロケーションを保存することが可能です。エンドデバイスのフレームペイロードから供給される自動ロケーション更新や、ロケーションを解決する他の様々な手段の次に、ロケーションを手動で設定することも可能です。このフォームを使用して、このロケーションタイプを更新することができます", - "console.views.device-location.index.setDeviceLocation": "エンドデバイスの位置を設定します", - "console.views.device-overview.index.failedAccessOtherHostDevice": "アクセスしようとしたエンドデバイスは別のクラスタに登録されているため、そのホストコンソールを使用してアクセスする必要があります", - "console.views.gateway-add.index.gtwOnboardingDescription": "ゲートウェイを登録して、近くのエンドデバイスとネットワーク間のデータトラフィックを可能にします。{break}(ブレイク 詳しくは、Adding Gateways のガイドをご覧ください", + "console.views.admin-packet-broker.messages.network": "", + "console.views.admin-packet-broker.messages.listNetwork": "", + "console.views.admin-packet-broker.messages.listNetworkDesc": "", + "console.views.admin-packet-broker.messages.unlistNetwork": "", + "console.views.admin-packet-broker.messages.confirmUnlist": "", + "console.views.admin-packet-broker.messages.Are you sure you want to unlist your network in Packet Broker?{lineBreak}This will hide your network. Other network administrators will not be able to see your network to configure routing policies.": "", + "console.views.admin-packet-broker.messages.routingPolicyInformation": "", + "console.views.admin-packet-broker.messages.defaultRoutingPolicySet": "", + "console.views.admin-packet-broker.messages.routingPolicySet": "", + "console.views.admin-packet-broker.messages.defaultRoutingPolicy": "", + "console.views.admin-packet-broker.messages.devAddressBlock": "", + "console.views.admin-packet-broker.messages.devAddressBlocks": "", + "console.views.admin-packet-broker.messages.lastPolicyChange": "", + "console.views.admin-packet-broker.messages.networkId": "", + "console.views.admin-packet-broker.messages.routingPolicyFromThisNetwork": "", + "console.views.admin-packet-broker.messages.routingPolicyToThisNetwork": "", + "console.views.admin-packet-broker.messages.saveRoutingPolicy": "", + "console.views.admin-packet-broker.messages.noPolicySet": "", + "console.views.admin-packet-broker.messages.prefixes": "", + "console.views.admin-packet-broker.messages.homeNetworkClusterId": "", + "console.views.admin-packet-broker.messages.backToAllNetworks": "", + "console.views.admin-packet-broker.messages.deregisterNetwork": "", + "console.views.admin-packet-broker.messages.confirmDeregister": "", + "console.views.admin-packet-broker.messages.Are you sure you want to deregister your network from Packet Broker?{lineBreak}This will permanently delete<.b> all routing policies and may stop traffic from flowing.{lineBreak}Traffic may still be forwarded to your network based on default routing policies configured by forwarders.": "", + "console.views.admin-packet-broker.messages.defaultGatewayVisibility": "", + "console.views.admin-packet-broker.messages.gatewayVisibilityInformation": "", + "console.views.admin-packet-broker.messages.defaultGatewayVisibilitySet": "", + "console.views.admin-packet-broker.messages.packetBrokerStatusPage": "", + "console.views.application-add.index.appDescription": "", + "console.views.application-integrations-lora-cloud.index.loraCloudInfoText": "", + "console.views.application-integrations-lora-cloud.index.officialLoRaCloudDocumentation": "", + "console.views.application-integrations-lora-cloud.index.dasDescription": "", + "console.views.application-integrations-lora-cloud.index.glsDescription": "", + "console.views.application-integrations-mqtt.index.publicAddress": "", + "console.views.application-integrations-mqtt.index.publicTlsAddress": "", + "console.views.application-integrations-mqtt.index.generateApiKey": "", + "console.views.application-integrations-mqtt.index.goToApiKeys": "", + "console.views.application-integrations-mqtt.index.mqttInfoText": "", + "console.views.application-integrations-mqtt.index.connectionCredentials": "", + "console.views.application-integrations-mqtt.index.mqttIntegrations": "", + "console.views.application-integrations-mqtt.index.officialMqttWebsite": "", + "console.views.application-integrations-mqtt.index.mqttServer": "", + "console.views.application-integrations-mqtt.index.host": "", + "console.views.application-integrations-mqtt.index.connectionInfo": "", + "console.views.application-integrations-pubsub-edit.index.editPubsub": "", + "console.views.application-integrations-pubsub-edit.index.updateSuccess": "", + "console.views.application-integrations-pubsub-edit.index.deleteSuccess": "", + "console.views.application-integrations-webhook-add-choose.index.chooseTemplate": "", + "console.views.application-integrations-webhook-add-choose.index.customTileDescription": "", + "console.views.application-integrations-webhook-add-form.index.addCustomWebhook": "", + "console.views.application-integrations-webhook-add-form.index.addWebhookViaTemplate": "", + "console.views.application-integrations-webhook-add-form.index.customWebhook": "", + "console.views.application-overview.index.failedAccessOtherHostApplication": "", + "console.views.device-general-settings.application-server-form.index.skip": "", + "console.views.device-general-settings.application-server-form.index.include": "", + "console.views.device-general-settings.application-server-form.index.default": "", + "console.views.device-general-settings.application-server-form.index.skipCryptoTitle": "", + "console.views.device-general-settings.messages.isTitle": "", + "console.views.device-general-settings.messages.isDescription": "", + "console.views.device-general-settings.messages.isDescriptionMissing": "", + "console.views.device-general-settings.messages.asTitle": "", + "console.views.device-general-settings.messages.asDescription": "", + "console.views.device-general-settings.messages.asDescriptionMissing": "", + "console.views.device-general-settings.messages.asDescriptionOTAA": "", + "console.views.device-general-settings.messages.jsTitle": "", + "console.views.device-general-settings.messages.jsDescription": "", + "console.views.device-general-settings.messages.jsDescriptionMissing": "", + "console.views.device-general-settings.messages.jsDescriptionOTAA": "", + "console.views.device-general-settings.messages.nsTitle": "", + "console.views.device-general-settings.messages.nsDescription": "", + "console.views.device-general-settings.messages.nsDescriptionMissing": "", + "console.views.device-general-settings.messages.deleteSuccess": "", + "console.views.device-general-settings.messages.deleteFailure": "", + "console.views.device-general-settings.messages.activationModeUnknown": "", + "console.views.device-general-settings.messages.notInCluster": "", + "console.views.device-general-settings.messages.updateSuccess": "", + "console.views.device-general-settings.messages.keysResetWarning": "", + "console.views.device-general-settings.messages.unclaimFailure": "", + "console.views.device-general-settings.messages.validateSessionKey": "", + "console.views.device-general-settings.messages.resetUsedDevNonces": "", + "console.views.device-general-settings.messages.resetUsedDevNoncesModal": "", + "console.views.device-general-settings.messages.resetSuccess": "", + "console.views.device-general-settings.messages.resetFailure": "", + "console.views.device-general-settings.network-server-form.index.resetTitle": "", + "console.views.device-general-settings.network-server-form.index.resetButtonTitle": "", + "console.views.device-general-settings.network-server-form.index.resetSuccess": "", + "console.views.device-general-settings.network-server-form.index.resetFailure": "", + "console.views.device-general-settings.network-server-form.index.modalMessage": "", + "console.views.device-import.index.noTemplatesTitle": "", + "console.views.device-import.index.noTemplates": "", + "console.views.device-location.index.locationInfoTitle": "", + "console.views.device-location.index.locationInfo": "", + "console.views.device-location.index.setDeviceLocation": "", + "console.views.device-overview.index.failedAccessOtherHostDevice": "", + "console.views.gateway-add.index.gtwOnboardingDescription": "", "console.views.gateway-data.index.gtwData": "", "console.views.gateway-general-settings.messages.basicTitle": "", "console.views.gateway-general-settings.messages.basicDescription": "", @@ -998,7 +998,7 @@ "console.views.gateway-general-settings.messages.techContactDescription": "", "console.views.gateway-general-settings.messages.deleteGatewayDefaultMessage": "", "console.views.gateway-general-settings.messages.unclaimAndDeleteGateway": "", - "console.views.organization-add.index.orgDescription": "組織は、複数のユーザーをグループ化し、そのユーザーに対して集合的な権利を割り当てるために使用されます。組織は、アプリケーションやゲートウェイのコラボレーターとして設定することができます。これにより、ユーザーのグループに対して、エンティティに対する権利の付与や取り消しを簡単に行うことができます。詳しくは、Organization Managementのガイドをご覧ください", + "console.views.organization-add.index.orgDescription": "", "console.views.user-settings-oauth-auth-settings.index.deleteButton": "", "console.views.user-settings-oauth-auth-settings.index.deleteSuccess": "", "console.views.user-settings-oauth-auth-settings.index.deleteFailure": "", @@ -1006,56 +1006,56 @@ "console.views.user-settings-oauth-auths.index.authorizationSettings": "", "console.views.user-settings-oauth-auths.index.accessTokens": "", "console.views.user-settings-profile.index.profileEdit": "", - "containers.collaborator-form.index.collaboratorIdPlaceholder": "コラボレーターを選択するために入力してください", + "containers.collaborator-form.index.collaboratorIdPlaceholder": "", "containers.collaborator-form.index.memberIdPlaceholder": "", "containers.collaborator-form.index.memberDeleteSuccess": "", "containers.collaborator-form.index.memberUpdateSuccess": "", "containers.collaborator-form.index.validateMember": "", "containers.collaborator-select.index.setYourself": "自分自身を{name}として設定する", "containers.fetch-table.index.errorMessage": "エラーが発生し、{entity, select, applications {applications} organizations {organizations} keys {API keys} collaborators {collaborators} devices {end devices} gateways {gateways} users {users} webhooks {webhooks} other {entities}}のリストを表示できませんでした。", - "lib.components.date-time.relative.justNow": "ただ今", - "lib.components.init.initializing": "初期化中...", - "lib.components.with-auth.errTooFewRights": "あなたのアカウントは、コンソールを使用するための十分な権利を持っていません", - "lib.components.with-auth.errTooFewRightsTitle": "不十分な権利", - "lib.components.with-auth.errStateRequested": "アカウントは管理者の承認が必要です。アカウントが承認されると、確認のメールが届きます", - "lib.components.with-auth.errStateRequestedTitle": "承認されていないアカウント", - "lib.components.with-auth.errStateRejected": "あなたのアカウントは管理者によって拒否されました", - "lib.components.with-auth.errStateRejectedTitle": "アカウントが拒否されました", - "lib.components.with-auth.errStateSuspended": "アカウントは管理者によって一時停止されています。アカウントの状態については、サポートにお問い合わせください", - "lib.components.with-auth.errStateSuspendedTitle": "アカウントの一時停止", - "lib.components.with-auth.errEmailValidation": "メールアドレスが認証されるまでは、アカウントが制限されます", - "lib.components.with-auth.errEmailValidationTitle": "電子メールの検証を保留中", - "lib.components.with-auth.resendValidationEmail": "確認メールを再送信する", - "lib.components.with-locale.switchingLanguage": "言語の切り替え...", - "lib.errors.error-messages.technicalDetails": "技術内容", - "lib.errors.error-messages.attachToSupportInquiries": "お問い合わせの際は、下記の技術資料を添付してください", - "lib.errors.error-messages.contactAdministrator": "リフレッシュしてもエラーが続く場合は、管理者に連絡してください", - "lib.errors.error-messages.contactSupport": "エラーが解消されない場合は、サポートまでご連絡ください", - "lib.errors.error-messages.inconvenience": "ご不便をおかけして申し訳ございません", - "lib.errors.error-messages.error": "エラー", - "lib.errors.error-messages.genericError": "未知のエラーが発生しました。後でもう一度試してみてください", - "lib.errors.error-messages.genericNotFound": "要求されたページが見つかりません", - "lib.errors.error-messages.subviewErrorExplanation": "このセクションを表示する際に問題がありました", - "lib.errors.error-messages.subviewErrorTitle": "申し訳ありませんでした!", - "lib.errors.error-messages.unknownErrorTitle": "未知のエラーが発生しました", - "lib.errors.error-messages.errorOccurred": "エラーが発生し、リクエストを完了することができませんでした", - "lib.errors.error-messages.errorId": "エラーID: {errorId}", - "lib.errors.error-messages.correlationId": "相関関係ID: {correlationId}", - "lib.errors.error-messages.loginFailedDescription": "ログインに失敗するようなエラーが発生しました。これは、サーバー側の設定ミスやブラウザのCookieの問題によるものかもしれません。再度ログインをお試しください", - "lib.errors.error-messages.loginFailedAbortDescription": "ログインプロバイダとの認証中に、ログイン処理が中断されました。以下のボタンからログインを再試行することができます", - "lib.errors.error-messages.connectionFailure": "現在、サーバーが使用できない状態になっています。これは、定期的なアップデートやメンテナンスのためかもしれません。詳細については、ステータスページ(利用可能な場合)を確認し、後でもう一度試してみてください", - "lib.errors.status-code-messages.4××": "クライアントエラー", - "lib.errors.status-code-messages.400": "不良リクエスト", - "lib.errors.status-code-messages.401": "無許可", - "lib.errors.status-code-messages.403": "禁じられた", - "lib.errors.status-code-messages.404": "見つかりませんでした", - "lib.errors.status-code-messages.409": "衝突", - "lib.errors.status-code-messages.429": "リクエストが多すます", - "lib.errors.status-code-messages.499": "クライアントのクローズドリクエスト", - "lib.errors.status-code-messages.500": "内部サーバーエラー", - "lib.errors.status-code-messages.501": "未実装", - "lib.errors.status-code-messages.503": "サービス利用不可", - "lib.errors.status-code-messages.504": "ゲートウェイのタイムアウト", + "lib.components.date-time.relative.justNow": "", + "lib.components.init.initializing": "", + "lib.components.with-auth.errTooFewRights": "", + "lib.components.with-auth.errTooFewRightsTitle": "", + "lib.components.with-auth.errStateRequested": "", + "lib.components.with-auth.errStateRequestedTitle": "", + "lib.components.with-auth.errStateRejected": "", + "lib.components.with-auth.errStateRejectedTitle": "", + "lib.components.with-auth.errStateSuspended": "", + "lib.components.with-auth.errStateSuspendedTitle": "", + "lib.components.with-auth.errEmailValidation": "", + "lib.components.with-auth.errEmailValidationTitle": "", + "lib.components.with-auth.resendValidationEmail": "", + "lib.components.with-locale.switchingLanguage": "", + "lib.errors.error-messages.technicalDetails": "", + "lib.errors.error-messages.attachToSupportInquiries": "", + "lib.errors.error-messages.contactAdministrator": "", + "lib.errors.error-messages.contactSupport": "", + "lib.errors.error-messages.inconvenience": "", + "lib.errors.error-messages.error": "", + "lib.errors.error-messages.genericError": "", + "lib.errors.error-messages.genericNotFound": "", + "lib.errors.error-messages.subviewErrorExplanation": "", + "lib.errors.error-messages.subviewErrorTitle": "", + "lib.errors.error-messages.unknownErrorTitle": "", + "lib.errors.error-messages.errorOccurred": "", + "lib.errors.error-messages.errorId": "", + "lib.errors.error-messages.correlationId": "", + "lib.errors.error-messages.loginFailedDescription": "", + "lib.errors.error-messages.loginFailedAbortDescription": "", + "lib.errors.error-messages.connectionFailure": "", + "lib.errors.status-code-messages.4××": "", + "lib.errors.status-code-messages.400": "", + "lib.errors.status-code-messages.401": "", + "lib.errors.status-code-messages.403": "", + "lib.errors.status-code-messages.404": "", + "lib.errors.status-code-messages.409": "", + "lib.errors.status-code-messages.429": "", + "lib.errors.status-code-messages.499": "", + "lib.errors.status-code-messages.500": "", + "lib.errors.status-code-messages.501": "", + "lib.errors.status-code-messages.503": "", + "lib.errors.status-code-messages.504": "", "lib.field-description-messages.idLocation": "", "lib.field-description-messages.freqPlanDescription": "周波数プランは、エンドデバイスやゲートウェイが使用するように設定されたデータレートを定義します。ゲートウェイとエンドデバイスが通信できるようにするためには、同じ周波数プランを使用することが重要です", "lib.field-description-messages.freqPlanLocation": "エンドデバイスやゲートウェイのメーカーは、特定のデバイスに適用される周波数プランに関する情報を提供するはずです。場合によっては、デバイス自体に印刷されていることもありますが、常にハードウェアマニュアルまたはデータシートに記載されているはずです", @@ -1259,7 +1259,7 @@ "lib.shared-messages.clear": "クリア", "lib.shared-messages.client": "クライアント", "lib.shared-messages.clientId": "", - "lib.shared-messages.close": "閉じる", + "lib.shared-messages.close": "", "lib.shared-messages.collaborator": "コラボレーター", "lib.shared-messages.collaboratorCounted": "{count, plural, one {コラボレーター} other {コラボレータース}}", "lib.shared-messages.collaboratorDeleteSuccess": "コラボレーターの削除", @@ -1311,7 +1311,7 @@ "lib.shared-messages.dataSheet": "", "lib.shared-messages.defineRights": "権利の定義", "lib.shared-messages.delayWarning": "遅延が短すぎます。ゲートウェイサーバーは下限値 ({minimumValue}ms) を使用します", - "lib.shared-messages.deleteGateway": "ゲートウェイの削除", + "lib.shared-messages.deleteGateway": "", "lib.shared-messages.unclaimAndDeleteDevice": "", "lib.shared-messages.deleteDevice": "", "lib.shared-messages.deleteApp": "", @@ -1353,7 +1353,7 @@ "lib.shared-messages.downlinkAck": "ダウンリンク ACK", "lib.shared-messages.downlinkFailed": "ダウンリンクに失敗しました。", "lib.shared-messages.downlinkFrameCount": "ダウンリンクのフレームカウント", - "lib.shared-messages.downloadGlobalConf": "global_conf.json のダウンロード", + "lib.shared-messages.downloadGlobalConf": "", "lib.shared-messages.downlinkNack": "裸のダウンリンク", "lib.shared-messages.downlinkPush": "ダウンリンクプッシュ", "lib.shared-messages.downlinkQueueInvalidated": "ダウンリンクキューが無効", @@ -1391,7 +1391,7 @@ "lib.shared-messages.eventUplinkMessageDesc": "アップリンクメッセージをアプリケーションで受信した場合", "lib.shared-messages.eventUplinkNormalizedDesc": "正規化されたアップリンクペイロード", "lib.shared-messages.eventsCannotShow": "イベントを表示できません", - "lib.shared-messages.expand": "拡げる", + "lib.shared-messages.expand": "", "lib.shared-messages.expiry": "期限切れ", "lib.shared-messages.exportJson": "JSONとしてエクスポート", "lib.shared-messages.external": "外部", @@ -1409,8 +1409,8 @@ "lib.shared-messages.frequencyPlanWarning": "周波数プランを選択しないと、ゲートウェイからのパケットは正しく処理されません", "lib.shared-messages.furtherResources": "その他のリソース", "lib.shared-messages.gateway": "ゲートウェイ", - "lib.shared-messages.gatewayDeleted": "ゲートウェイ削除", - "lib.shared-messages.gatewayDeleteError": "ゲートウェイ削除エラー", + "lib.shared-messages.gatewayDeleted": "", + "lib.shared-messages.gatewayDeleteError": "", "lib.shared-messages.gatewayOverview": "", "lib.shared-messages.gatewayDescDescription": "オプションのゲートウェイの説明;ゲートウェイについてのメモを保存するために使用することもできます", "lib.shared-messages.gatewayDescPlaceholder": "新しいゲートウェイの説明", @@ -1437,8 +1437,8 @@ "lib.shared-messages.generateAPIKeyCups": "CUPSのAPIキーを生成", "lib.shared-messages.generateAPIKeyLNS": "LNSのAPIキーを生成", "lib.shared-messages.getSupport": "サポートを受ける", - "lib.shared-messages.globalConfFailed": "global_conf.json のダウンロードに失敗しました", - "lib.shared-messages.globalConfFailedMessage": "未知のエラーが発生し、global_conf.json をダウンロードできませんでした", + "lib.shared-messages.globalConfFailed": "", + "lib.shared-messages.globalConfFailedMessage": "", "lib.shared-messages.grantAdminStatus": "管理者権限を付与", "lib.shared-messages.grpcService": "gRPCサービス", "lib.shared-messages.gsServerAddressDescription": "接続先のゲートウェイサーバのアドレス", @@ -1529,7 +1529,7 @@ "lib.shared-messages.newPasswordConfirm": "", "lib.shared-messages.next": "次へ", "lib.shared-messages.noActivityYet": "まだ活動はしていません", - "lib.shared-messages.noData": "データはありません", + "lib.shared-messages.noData": "", "lib.shared-messages.noDesc": "このエンドデバイスには説明がありません", "lib.shared-messages.noEvents": "
{entityId}
からのイベント待ち...", "lib.shared-messages.noLocationYet": "", @@ -1708,7 +1708,7 @@ "lib.shared-messages.topEntitiesError": "", "lib.shared-messages.tokenSet": "トークンの設定", "lib.shared-messages.tokenUpdated": "トークンの更新", - "lib.shared-messages.totalEndDevices": "エンドデバイスの追加", + "lib.shared-messages.totalEndDevices": "", "lib.shared-messages.traffic": "トラフィック", "lib.shared-messages.troubleshooting": "トラブルシューティング", "lib.shared-messages.type": "タイプ", @@ -2247,15 +2247,20 @@ "error:pkg/devicerepository/store/bleve:corrupted_index": "インデックスファイルが破損しています", "error:pkg/devicerepository/store/bleve:end_device_profile_not_found": "ベンダーID `{vendor_id}` およびベンダープロファイルID `{vendor_profile_id}` のエンドデバイスプロファイルが見つかりません", "error:pkg/devicerepository/store/bleve:invalid_number_of_profiles": "無効なプロファイル数 `{number}`", - "error:pkg/devicerepository/store/bleve:multiple_identifiers": "リクエストに複数の識別子が見つかりました。EndDeviceVersionIdentifiersまたはEndDeviceProfileIdentifiersのいずれかを使用してください", + "error:pkg/devicerepository/store/bleve:missing_profile_identifiers": "", "error:pkg/devicerepository/store/remote:band_not_found": "バンド `{band_id}` が見つかりません", + "error:pkg/devicerepository/store/remote:band_not_found_for_region": "", "error:pkg/devicerepository/store/remote:brand_not_found": "ブランド `{brand_id}` が見つかりません", + "error:pkg/devicerepository/store/remote:brand_with_vendor_id_not_found": "", "error:pkg/devicerepository/store/remote:firmware_version_not_found": "モデル `{brand_id}/{model_id}` に対するファームウェアのバージョン `{firmware_version}` が見つかりません", + "error:pkg/devicerepository/store/remote:missing_profile_identifiers": "", "error:pkg/devicerepository/store/remote:model_not_found": "モデル `{brand_id}/{model_id}` が見つかりません", "error:pkg/devicerepository/store/remote:no_codec": "ファームウェアバージョン `{firmware_version}` とバンド `{band_id}` に対して規定された符号化方式がありません。", "error:pkg/devicerepository/store/remote:no_decoder": "コーデック`{codec_id}`にはデコーダが定義されていません", "error:pkg/devicerepository/store/remote:no_encoder": "コーデック`{codec_id}`にはエンコーダが定義されていません", "error:pkg/devicerepository/store/remote:no_profile_for_band": "デバイスにはバンド `{band_id}` のプロファイルがありません", + "error:pkg/devicerepository/store/remote:no_template_identifiers": "", + "error:pkg/devicerepository/store/remote:vendor_profile_id_not_found": "", "error:pkg/devicerepository/store:regional_parameters_version": "不明な地域パラメータバージョン`{phy_version}`", "error:pkg/devicerepository:brand_not_found": "バンド `{band_id}` が見つかりません", "error:pkg/devicerepository:model_not_found": "モデル `{brand_id}/{model_id}` が見つかりません",